0%

本文已在丁牛网安实验室FreeBuf专栏 DigApis安全 中首发!引用转发请注明 “原文来自:DigApis安全 m0nst3r”字样,谢谢!

[TOC]

wfuzz 基本用法


暴破文件和路径

wfuzz可以用来查找一个web server中的隐藏的文件和路径,来扩大攻击面。值得注意的是,这种测试的成功与否很大程度上要依赖于使用的字典。
但是,一个web server的平台是有限的,还有一些是默认安装,再加上一些已知的资源比如日志文件,管理路径等等,我们还是可以在猜测到发现很多东西。因此,暴破文件的路径还是可行的。

wfuzz自带一些字典文件,更多的字典可以参考下面两个开放的git:

使用wfuzz暴力猜测目录的命令如下:
$ wfuzz -w /usr/share/wfuzz/wordlist/general/common.txt http://testphp.vulnweb.com/FUZZ

使用wfuzz暴力猜测文件的命令如下:
$ wfuzz -w /usr/share/wfuzz/wordlist/general/common.txt http://testphp.vulnweb.com/FUZZ.php

Read more »

本文已在丁牛网安实验室FreeBuf专栏 DigApis安全 中首发!引用转发请注明 “原文来自:DigApis安全 m0nst3r”字样,谢谢!

[TOC]

wfuzz 库


wfuzz库参数

在wfuzz库中包含所有 wfuzz命令行的参数。

CLI Option Library Option
<URL> url=”url”
–recipe <filename> recipe=”filename”
-oF <filename> save=”filename”
-f filename,printer printer=(“filename”,”printer”)
–dry-run dryrun=True
-p addr proxies=[(“ip”,”port”,”type”)]
-t N concurrent=N
-s N delay=0.0
-R depth rlevel=depth
–follow follow=True
-Z scanmod=True
–req-delay N req_delay=N
–conn-delay N conn_delay=N
–script=<plugins> script=”plugins”
–script-args n1=v1,… script_args={n1:v1,}
-m iterator iterator=”iterator”
-z payload payloads=[(“name”,{default=””,encoder=[“md5”]},slice=””),]
-V alltype allvars=”alltype”
-X method method=”method”
–hc/hl/hw/hh N[,N]+ hc/hl/hw/hh=[N,N]
–sc/sl/sw/sh N[,N]+ sc/sl/sw/sh=[N,N]
–ss/hs regex ss/hs=”regex”
–filter <filter> filter=”filter exp”
–prefilter <filter> prefilter=”filter exp”
-b cookie cookie=[“cookie1=value1”,]
-d postdata postdata=”postdata”
-H header headers=[(“header1”,”value1”),]
–basic/ntlm/digest auth auth=(“basic”,”user:pass”)

这些参数可以在这些主库的接口中直接使用:fuzz, payload, session


测试一个URL

Read more »

本文已在丁牛网安实验室FreeBuf专栏 DigApis安全 中首发!引用转发请注明 “原文来自:DigApis安全 m0nst3r”字样,谢谢!

[TOC]


wfuzz教程

这个教程主要内容是来自wfuzz官方文档。之所以写这个,是因为大多数的国内文章并没有对这个工具进行详细的说明。个人英文还算可以,所以抖胆翻译一下,加上自己的一些操作,一方面加深下自己对这个工具的熟练程度,另一方面方便广大初学者学习。
感觉这个工具比平时使用的御剑灵活很多(如果参数都弄明白的话),总之,作为渗透测试信息收集的一个环节,它还是有用武之地的。

这个教程本来想弄一篇文章,但是实在是太多了,所以借鉴了一下官方文档的分节,把这个教程做成了一个系列,一共四个部分,分别是:

  • 初识wfuzz:看完这个,你应该可以使用比较简单的命令来做一些任务了。

  • wfuzz 基本用法:看完这个的话,你应该可以从容使用wfuzz来做一些常用扫描器做不了的活,而且觉得wfuzz是个好东西。

  • wfuzz 高级用法:看完这个,你应该就可以玩弄wfuzz于手掌之中,各种小姿势让你在别人扫不成的时候装装X。

  • wfuzz 库:看完这个,不,能去仔细学习这个的同学,我就不说了,此类人圈内统称”大婊哥“,小弟在这只是抛砖引玉了。


简介

wfuzz 是一款Python开发的Web安全测试工具
wfuzz不仅仅是一个web扫描器:

Read more »

本文已在丁牛网安实验室FreeBuf专栏 DigApis安全 中首发!引用转发请注明 “原文来自:DigApis安全 m0nst3r”字样,谢谢!

[TOC]

wfuzz 高级用法


wfuzz全局配置

wfuzz的全局配置文件位于~/.wfuzz/wfuzz.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─[michael@parrot]─[~/.wfuzz]
└──╼ $cat wfuzz.ini
[kbase]
discovery.blacklist = .svg-.css-.js-.jpg-.gif-.png-.jpeg-.mov-.avi-.flv-.ico #这里配置忽略的后缀,用 - 号分隔

[connection]
concurrent = 50 #并发数
conn_delay = 90 #连接间隔
req_delay = 90 #请求间隔
retries = 3 #重试次数
user-agent = Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0 #UA,默认为Wfuzz/版本

[general]
default_printer = raw #默认输出格式
cancel_on_plugin_except = 1 #插件出错则退出
concurrent_plugins = 3 #最多同时指定的插件数量
lookup_dirs = /usr/share/wfuzz/wordlist,. #查找字典的目录,若让wfuzz自动查找字典,则在命令行中只指定字典名字即可
encode_space = 1 #编码空格

[plugins]
bing_apikey = #设置bing API在key

Iterators:组合payloads

不同的payload可以通过-m参数指定的方式组合起来,在wfuzz中,提供这种组合能力的功能的,我们称为迭代器。
关于wfuzz中所有可用的iterators可参考重要关键词部分。

Read more »

[TOC]

程序

局部变量

1
2
3
4
5
6
7
8
#include<stdio.h>
int main(){
int x;
printf("Enter X:\n");
scanf("%d",&x);
printf("You entered %d...\n",x);
return 0;
}

全局变量

1
2
3
4
5
6
7
8
9
#include<stdio.h>
//now,x is global variable
int x;
int main(){
printf("Enter X:\n");
scanf("%d",&x);
printf("You entered %d...\n",x);
return 0;
}

scanf()函数的状态监测

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main(){
int x;
printf ("Enter X:\n");
if (scanf ("%d", &x)==1)
printf ("You entered %d...\n", x);
else
printf ("What you entered? Huh?\n");
return 0;
};

x86

x86局部变量

Read more »

[TOC]

数值比较

主要程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
void f_signed(int a,int b)
{
if(a>b)
printf("a>b\n");
if(a==b)
printf("a==b\n");
if(a<b)
printf("a<b\n");
}
void f_unsigned(unsigned int a,int b)
{
if(a>b)
printf("a>b\n");
if(a==b)
printf("a==b\n");
if(a<b)
printf("a<b\n");
}
int main()
{
f_signed(1,2);
f_unsigned(1,2);
return 0;
}

x86

x86+msvc

关闭优化选项时,可得到f_signed()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
_a$ = 8
_b$ = 12
_f_signed PROC
push ebp
mov ebp,esp
mov eax,DWORD PTR _a$[ebp]
cmp eax,DWORD PTR _a$[ebp]
jle SHORT $LN3@f_signed
push OFFSET $SG737 ;'a>b'
call _printf
add esp,4
$LN3@f_signed:
mov ecx,DWORD PTR _a$[ebp]
cmp ecx,DWORD PTR _b$[ebp]
jne SHORT $LN2@f_signed
push OFFSET $SG739 ;'a==b'
call _printf
add esp,4
$LN2@f_signed:
mov edx,DWORD PTR _a$[ebp]
cmp edx,DWORD PTR _a$[ebp]
jge SHORT $$LN4@f_signed
push OFFSET $SG741 ;'a<b'
call _prinf
$LN4@f_signed:
pop ebp
ret 0

_f_signed ENDP

第一个条件转一会领是JLE,即“Junp if Less or Equal”。如果上一条CMP指令的第一个操作数表达式小于或等于(不大于)第二个表达式,JLE将跳转到指令所标明的地址;如果不满足上述条件,则运行下一条指令,就本例而言程序将会调用printf()函数,第二个条件转移指令是JNE,”Jump if Not Equal“,如果上一条CMP指令的两个操作符不相等,则进行相应跳转。
第三个转移指令是JGE,即”Jump if Greater or Equal“,如果CMP的第一个表达式大于或等于第二个表达式(不小于),则进行跳转。这段程序里,如果三个跳转的判断条件都不满足,将不会调用pringtf()函数;不过除非进行特殊干预,,否则这种情况应该不会发生。
现在我们观察 f_unsigned()函数的汇编指令。f_unsigned()函数和 f_signed()函数大体相同。它们的区别集中体现在条件转移指令上:f_unsinged()函数的使用的条件转移指令是 JBE 和 JAE,而 f_signed()函数使用的条件转移指令则是 JLE 和 JGE。
使用 GCC 编译上述程序,可得到 f_unsigned()的汇编指令如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
_a$=8   ;size=4
_b$=12 ;size=4
_f_unsifned PROC
push ebp
mov ebp,esp
mov eax,DWORD PTR _a$[ebp]
cmp eax,DWORD PTR _b$[ebp]
jbe SHORT $LN3@f _unsigned
push OFFSET $SG2761 'a>b'
call _printf
add esp,4
$LN3@f _unsigned:
mov ecx,DWORD PTR _a$[ebp]
cmp ecx,DWORD PTR _b$[ebp]
jne SHORT $LN2@f_unsigned
push OFFSET $SG2763 ; 'a==b'
call _printf
add esp, 4
$LN2@f_unsigned:
mov edx,DWORD PTR _a$[ebp]
cmp edx,DWORD PTR _b$[ebp]
jae SHORT $LN4@f_unsigned
push OFFSET $SG2765 ; 'a<b'
call _printf
add esp, 4
LN4@f_unsigned:
pop ebp
Ret 0
_f_unsigned ENDP
Read more »

[TOC]

case陈述式较少的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

voif f( int a)
{
switch (a)
{
case 0: printf("zero\n"); break;
case 1: printf("one\n"); break;
case 2: printf("two\n"); break;
default: printf("sth unknown\n"); break;
}
}

int main()
{
f(2);
}

x86

未优化的MSVC

指令清单如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
tv64 = -4			; size = 4
_a$ = 8 ; size = 4
_f PROC
push ebp
mov ebp,esp
push ecx
mov eax, DWORD PTR _a$[ebp]
mov DWORD PTR tv64[ebp], eax
cmp DWORD PTR tv64[ebp], 0
je SHORT $LN4@f
cmp DWORD PTR tv64[ebp], 1
je SHORT $LN3@f
cmp DWORD PTR tv64[ebp], 2
je SHORT $LN2@f
jmp SHORT $LN1@f
$LN4@f:
push OFFSET $SG739 ; 'zero', 0aH, 00H
call _printf
add esp,4
jmp SHORT $LN7@f
$LN3@f:
push OFFSET $SG741 ; 'one', 0aH, 00H
call _printf
add esp,4
jmp SHORT $LN7@f
$LN2@f:
push OFFSET $SG743 ; 'two', 0aH, 00H
call _printf
add esp,4
jmp SHORT $LN7@f
$LN1@f:
push OFFSET $SG745 ; 'sth unknown', 0aH, 00H
call _printf
add esp,4
jmp SHORT $LN7@f
$LN7@f:
mov esp, ebp
pop ebp
ret 0
_f ENDP

上面这个函数的源程序相当于:

1
2
3
4
5
6
7
8
9
void f (int a)
{
if (a==0)
printf ("zero\n");
else if (a==1)
printf ("one\n");
else if (a==2)
printf ("two\n");
elseprintf ("sth unknown\n"); };

如果仅从汇编代码入手,那么我们无法判断上述函数是一个判断表达式较少的switch()语句、还是一组 if()语句。确实可以认为,switch()语句是一种旨在简化大量嵌套if()语句而设计的语法糖。
若用GCC 4.4.1编译器编译这个程序,无论是否启用其最大程度优化的选项-O3,生成的汇编代码也和 MSVC 编译出来的代码没有什么区别。

Read more »

[TOC]

参数获取

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int f ( int a, int b, int c)
{
return a*b+c;
}

int main()
{
printf("%d\n", f(1,2,3));
return 0;
}

x86

MSVC

MSVC编译后的指令清单如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
_TEXT	SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
_f PROC
push ebp
mov ebp,esp
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _b$[ebp]
add eax, DWORD PTR _c$[ebp]
pop ebp
ret 0
_f ENDP

_main PROC
push ebp
push ebp,esp
push 3 ; 3rd argument
push 2 ; 2nd argument
push 1 ; 1st argument
call _f
add esp, 12
push eax
push OFFSET $SG2463 ; '$d', 0aH, 00H
call _printf
add esp, 8
; return 0
xor eax, eax
pop ebp
ret 0
_main ENDP

main()函数把 3 个数字推送入栈,然后调用了f(int, int, int)。被调用方函数f()通过_a$=8一类的汇编宏访问所需参数以及函数自定义的局部变量。只不过从被调用方函数的数据栈的角度来看,外部参考的偏移量是正值,而局部变量的偏移量是负值。可见,当需要访问栈帧(stack frame)以外的数据时,被调用方函数可把汇编宏(例如_a$)与EBP寄存器的值相加,从而求得所需地址。
当变量 a 的值存入EAX寄存器之后,f()函数通过各参数的地址依次进行乘法和加法运算,运算结果 一直存储于 EAX 寄存器。此后 EAX 的值就可以直接作为返回值传递给调用方函数。调用方函数 main()再 把 EAX 的值当作参数传递给 printf()函数。

GCC

Read more »

[TOC]

程序

三个参数

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
printf("a=%d; b=%d; c=%d", 1, 2, 3);
return 0;
}

九个参数

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
printf("a=%d; b=%d; c=%d; d=%d; e=%d; f=%d; g=%d; h=%d\n", 1, 2, 3, 4, 5, 6, 7, 8);
return 0;
};

我们用这个程序来演示它的参数传递过程。

x86

x86:传递3个参数

MSVC
Read more »

[TOC]

栈是计算机科学李最重要的且最基础的数据结构之一。
从技术上讲,栈就是CPU寄存器里面的某个指针所指向的一片内存区域。这里所说的某个指针通常位于x86/x64平台的ESP寄存器/RSP寄存器,以及ARM平台的SP寄存器
操作站最常见的指令是PUSHPOP,在 x86 和 ARM Thumb 模式的指令集里都有这两条指令。
PUSH指令会对ESP/RSP/SP寄存器的值进行减法运算,使之减去4(32位)或8(64位),然后将操作数写到上述寄存器里的指针所指向的内存中。
POP指令是PUSH的逆操作:他先从栈指针(Stack Pionter,上面三个寄存器之一)指向的内存中读取数据,用以备用(通常是写到其他寄存器里面),然后再将栈指针的数值加上4或8.
在分配栈的空间之后,栈指针,即Stack Pointer所指向的地址是栈的底部。PUSH将减少栈指针的数值,而POP会增加它的数值。栈的“底”实际上使用的是整个栈的最低地址,即是整个栈的启始内存地址。
ARM的栈分为递增栈和递减栈。递减栈(descending stack)的首地址是栈的最高地址,栈向低地址增长,栈指针的值随栈的增长而减少,如STMFA/LMDFA、STMFD/LDMFD、STMED、LDMEA等指令,都是递增栈的操作指令。

栈的用途

保存函数结束时的返回地址

x86

当程序使用call指令调用其他函数时,call指令结束后的返回地址将被保存到栈里,在call所调用的函数结束之后,程序将执行无条件跳转指令,跳转到这个返回地址。
call指令等价于“PUSH返回地址”和“JMP函数地址”的指令对
被调用函数里的RET指令,会从栈中读取返回地址,然后跳转到这个这个地址,就相当于“POP返回地址”+“JMP返回地址”指令。
栈是有限的,溢出它很容易。直接使用无线递归,栈就会满:

1
2
3
4
void f()
{
f();
}

如果使用MSVC2008编译上面的问题程序,就会得到报告:

​ c:\tmp6>cl ss.cpp /Fass.asm
​ Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
​ Copyright (C) Microsoft Corporation. All rights reserved.
​ ss.cpp
​ c:\tmp6\ss.cpp(4) : warning C4717:’f’ : recursive on all control paths. Function will cause runtime stack overflow
但它还是会生成汇编文件

1
2
3
4
5
6
7
8
9
10
11
?f@@YAXXZ PROC              ; f
; File c:\tmp6\ss.cpp
; Line 2
push ebp
mov ebp, esp
; Line 3
call ?f@@YAXXZ ; f
; Line 4
pop ebp
ret 0
?f@@YAXXZ ENDP ; f
Read more »