前言
比赛时间:2024.10.6 - 2025.11.3
Misc
关注 DK 盾谢谢喵
关注微信公众号, 发送 0xGame 2024 获取 flag:0xGame{W31c0m3_70_0x64m3_2024_5p0n50r3d_8y_dkdun}
0xGame2048
提示:通过一点也不 可靠的途径,我们提前截获了 0xGame2048 的题目,据说这就是那时候的 base 编码(附件:0xGame2048.txt)
读取附件得到Жఱ൲ඌיય೬ࢶЖۍךะtঋළม۹ρԊҽඹ
根据提示搜索 base2048,发现网站Base2048 Encoder And Decoder (nerdmosis.com)
对其解码后得到 0xGame{W3lc0me_t0_0xG4me!!!}
加密的压缩包?
我其实也不会修压缩包,我自己新建了一个压缩包,也是只包含一个 flag 文件,39 字节的,并用 0xGame 加密
然后用 010Editor 进行分析比较,发现末尾部分,有一处不同,一个是 5B,一个是 59,因此将 5B 改为 59 发现压缩包竟然可以解压了
查阅发现这个位置是中央目录开始位置相对位移
总之,解压后得到 flag:0xGame{M@ybe_y0u_ar2_t4e_mAsTer_0f_Z1p}
Crypto
Caesar Cipher
密文:0yHbnf{Uif_Cfhjoojoh_Pg_Dszqup}
提示:凯撒加密。
尝试解密,发现 key=1,获得 flag:0xgame{the_beginning_of_crypto}
Code
获取附件打开得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from Crypto.Util.number import bytes_to_longfrom base64 import b64encodefrom secret import flagmsg = flag.encode() length = len (msg) assert length%4 == 0 block = length//4 m = [ msg[ block*(i) : block*(i+1 ) ] for i in range (4 ) ] m0 = m[0 ] m1 = bytes_to_long(m[1 ]) m2 = m[2 ].hex () m3 = b64encode(m[3 ]) print (f'm0 = {m0} \nm1 = {m1} \nm2 = {m2} \nm3 = {m3} ' )''' m0 = b'0xGame{73d7' m1 = 60928972245886112747629873 m2 = 3165662d393339332d3034 m3 = b'N2YwZTdjNGRlMX0=' '''
读代码:将 flag 拆分为相等的 4 部分m0,m1,m2,m3,4 部分分别:
m0 不处理。
m1 先转为 16 进制编码,再转换为 10 进制。只需要先 10 进制转 16 进制,再 16 进制解码即可。
m2 转 16 进制编码。
m3 用 base64 编码。
解码后拼接得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from Crypto.Util.number import *from base64 import b64decodem0 = b"0xGame{73d7" m1 = 60928972245886112747629873 m2 = "3165662D393339332D3034" m3 = b"N2YwZTdjNGRlMX0=" m0 = m0 m1 = long_to_bytes(m1) m2 = bytes .fromhex(m2) m3 = b64decode(m3) print ((m0 + m1 + m2 + m3).decode())
Code-Vigenere
获取附件打开得到:
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 from secret import flagfrom os import urandomfrom base64 import b64encodedef Encrypt (msg, key ): Lenth = len (key) result = '' upper_base = ord ('A' ) lower_base = ord ('a' ) KEY = [ord (key.upper()[_]) - upper_base for _ in range (Lenth)] index = 0 for m in msg: tmp_key = KEY[index%Lenth] if not m.isalpha(): result += m continue if m.isupper(): result += chr (upper_base + (ord (m) - upper_base + tmp_key) % 26 ) else : result += chr (lower_base + (ord (m) - lower_base + tmp_key) % 26 ) index += 1 return result key = b64encode(urandom(6 ))[:5 ].decode() print (Encrypt(flag,key))
维基尼尔加密跳过非字母,由于已知 flag 前 6 位为0xGame 且加密密钥只有 5 位,只需要分别找出密钥各个位使得前几位正常解密即可
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 from os import urandomfrom base64 import b64encodedef Encrypt (msg: str , key ): Lenth = len (key) result = "" upper_base = ord ("A" ) lower_base = ord ("a" ) KEY = [ord (key.upper()[_]) - upper_base for _ in range (Lenth)] index = 0 for m in msg: tmp_key = KEY[index % Lenth] if not m.isalpha(): result += m continue if m.isupper(): result += chr (upper_base + (ord (m) - upper_base + tmp_key) % 26 ) else : result += chr (lower_base + (ord (m) - lower_base + tmp_key) % 26 ) index += 1 return result def Decrypt (msg: str , key ): Lenth = len (key) result = "" upper_base = ord ("A" ) lower_base = ord ("a" ) KEY = [ord (key.upper()[_]) - upper_base for _ in range (Lenth)] index = 0 for m in msg: tmp_key = KEY[index % Lenth] if not m.isalpha(): result += m continue if m.isupper(): result += chr (upper_base + (ord (m) - upper_base - tmp_key) % 26 ) else : result += chr (lower_base + (ord (m) - lower_base - tmp_key) % 26 ) index += 1 return result flag = "0lCcop{oyd94092-g8mq-4963-88b6-4helrxdhm6q7}" key = chr (ord ("a" ) + (ord ("l" ) - ord ("x" )) % 26 ) key += chr (ord ("A" ) + (ord ("C" ) - ord ("G" )) % 26 ) key += chr (ord ("a" ) + (ord ("c" ) - ord ("a" )) % 26 ) key += chr (ord ("a" ) + (ord ("o" ) - ord ("m" )) % 26 ) key += chr (ord ("a" ) + (ord ("p" ) - ord ("e" )) % 26 ) print (key) print (Decrypt(flag, "oWccl" ))
RSA-Baby
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 from Crypto.Util.number import bytes_to_long, getPrimefrom hashlib import md5from random import randintfrom gmpy2 import invert,gcddef MD5 (m ):return md5(str (m).encode()).hexdigest()def KeyGen (): Factor_BitLength = 30 q = getPrime(Factor_BitLength) p = getPrime(Factor_BitLength) N = p * q phi = (p-1 ) * (q-1 ) while True : e = randint(1 ,phi) if gcd(e,phi) == 1 : d = int (invert(e,phi)) break Pub_Key = (N,e) Prv_Key = (N,d) return Pub_Key,Prv_Key Pub,Prv = KeyGen() N = Pub[0 ] e = Pub[1 ] d = Prv[1 ] m = randint(1 ,N) c = pow (m,e,N) print (f'Pub_Key = {Pub} ' )print (f'Prv_Key = {Prv} ' )print (f'Encrypt_msg = {c} ' )''' Pub_Key = (547938466798424179, 80644065229241095) Prv_Key = (547938466798424179, 488474228706714247) Encrypt_msg = 344136655393256706 ''' flag = '0xGame{' + MD5(m) +'}'
既然已知私钥直接计算即可
1 2 3 4 5 6 7 c = 344136655393256706 d = 488474228706714247 N = 547938466798424179 m = pow (c, d, N) flag = "0xGame{" + MD5(m) + "}" print (f"Flag = {flag} " )
得到 flag:0xGame{6e5719c54cdde25ce7124e280803f938}
RSA-Easy
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 from Crypto.Util.number import bytes_to_long, getPrimefrom hashlib import md5from random import randintfrom gmpy2 import invert,gcddef MD5 (m ):return md5(str (m).encode()).hexdigest()def KeyGen (): Factor_BitLength = 30 q = getPrime(Factor_BitLength) p = getPrime(Factor_BitLength) N = p * q phi = (p-1 ) * (q-1 ) while True : e = randint(1 ,phi) if gcd(e,phi) == 1 : break Pub_Key = (N,e) return Pub_Key Pub = KeyGen() N = Pub[0 ] e = Pub[1 ] m = randint(1 ,N) c = pow (m,e,N) print (f'Pub_Key = {Pub} ' )print (f'Encrypt_msg = {c} ' )''' Pub_Key = (689802261604270193, 620245111658678815) Encrypt_msg = 289281498571087475 ''' flag = '0xGame{' + MD5(m) +'}'
尝试对 N 进行因式分解:
1 2 3 4 5 from sympy.ntheory import factorintnumber = 689802261604270193 factors = factorint(number) print (f"The prime factors of {number} are: {factors} " )
得到 689802261604270193=823642439*837502087
1 2 3 4 5 6 7 8 9 10 11 12 13 N, e = 689802261604270193 , 620245111658678815 c = 289281498571087475 phi = (823642439 - 1 ) * (837502087 - 1 ) d = invert(e, phi) m = pow (c, d, N) flag = "0xGame{" + MD5(m) + "}" print (f"Decrypt_msg = {m} " )print (f"Flag = {flag} " )
计算出私钥d:180714494322768091,密文m:302808065155328433,密文用 MD5 处理得到 flag:0xGame{5aa4603855d01ffdc5dcf92e0e604f31}。
Number Theory CRT | Review
问题:RSA,在 e 与 phi 不互素的条件下,求解 m
1 2 3 4 5 6 7 8 N = 1022053332886345327 p, q = 970868179 , 1052721013 e = 294200073186305890 c = 107033510346108389 phi = (p - 1 ) * (q - 1 ) print (f"gcd(e, phi) = {GCD(e, phi)} " )
由于 e 与 N 不互素,只能取 e gcd ( e , N ) e\over\gcd(e, N) g c d ( e , N ) e 的模逆即 2d,2 d ⋅ e 2 = ϕ ( N ) 2d\cdot {e\over2}=\phi(N) 2 d ⋅ 2 e = ϕ ( N )
1 2 3 4 D = inverse(e // 2 , phi) M = pow (c, D, N) print (f"M = {M} " )
这样就能求出 m 2 = m 2 d e = c 2 d m o d N m^2=m^{2de}=c^{2d}\mod N m 2 = m 2 d e = c 2 d m o d N , 现在只需解决这个二次剩余问题即可
先分解 N 质因数化为两个同余方程{ m 1 2 = a m o d p m 2 2 = a m o d q \begin{cases}m_{1}^2=a\mod p\\m_{2}^2=a\mod q\\\end{cases} { m 1 2 = a m o d p m 2 2 = a m o d q ,再用 CRT 求解即可。
1 2 3 4 5 6 7 8 9 10 def CRT (a, n ): N = 1 for i in range (len (a)): N *= n[i] x = 0 for i in range (len (a)): m = N // n[i] x += a[i] * m * inverse(m, n[i]) return x % N m = CRT([m1, m2], [p, q])
由于本题数据较小,求解 m~1~、m~2~可以用暴力破解
1 2 3 4 5 def brute_force (M, N ): M = M % N for m in range (2 , N): if pow (m, 2 , N) == M: return m
或者是 tonelli-shanks 算法:
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 def tonelli_shanks (n, p ): if pow (n, (p - 1 ) // 2 , p) != 1 : raise ValueError(f"{n} 不是模 {p} 的平方剩余" ) s = 0 q = p - 1 while q % 2 == 0 : q //= 2 s += 1 z = 2 while pow (z, (p - 1 ) // 2 , p) == 1 : z += 1 R = pow (n, (q + 1 ) // 2 , p) c = pow (z, q, p) t = pow (n, q, p) M = s while t != 1 : i = 0 temp = t while temp != 1 : temp = (temp * temp) % p i += 1 b = pow (c, 1 << (M - i - 1 ), p) R = (R * b) % p c = (b * b) % p t = (t * c) % p M = i return R
1 2 3 4 5 6 7 8 9 m1 = tonelli_shanks(M, p) m2 = tonelli_shanks(M, q) m = CRT([m1, m2], [p, q]) assert pow (m, e, N) == cprint (f"0xGame{{{MD5(m)} }}" )
Pwn
0. test your nc
在虚拟机中启动 linux 在终端输入 nc 47.97.58.52 40000 成功连接。
获得 flag:0xGame{928bb261-0a63-4389-b629-4d1f2f449848}
Web
ez_login
先输入账号密码用 BP 抓包,发送到 Intruder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /login HTTP/1.1 Host : 47.76.156.133:60084User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8Accept-Language : zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding : gzip, deflate, brContent-Type : application/x-www-form-urlencodedContent-Length : 29Origin : http://47.76.156.133:60084Connection : keep-aliveReferer : http://47.76.156.133:60084/loginUpgrade-Insecure-Requests : 1Priority : u=0, iusername=admin &password =admin
爆破发现,密码为 admin123。
获得 flag:0xGame{It_Is_Easy_Right?}
ez_sql
输入 http://47.76.152.109:60080/?id=1 order by 5# 不报错,但输入 http://47.76.152.109:60080/?id=1 order by 6# 报错,说明该表格有五列。
接下来就可以使用 union 了,先将前面的语句出错,就可以查自定义的语句了,http://47.76.152.109:60080/?id=1 and 1=0 union select 1, 2, 3, 4, 5 from users,测试发现可以回显。
先跑表 http://47.76.152.109:60080/?id=1 and 1=0 union select 1, 2, 3, 4, group_concat(name) from sqlite_master,获取表名flag,users。
再跑列http://47.76.152.109:60080/?id=1 and 1=0 union select 1, 2, 3, 4, group_concat(sql) from sqlite_master where name = 'flag' 得到 hacker,被过滤了,呜呜。
不加就是了,http://47.76.152.109:60080/?id=1 and 1=0 union select 1, 2, 3, 4, group_concat(sql) from sqlite_master,得到所有列,其中 flag 表只有 flag 列。
继续跑值 http://47.76.152.109:60080/?id=1 and 1=0 union select 1, 2, 3, 4, group_concat(flag) from flag
获得 flag:0xGame{Do_not_Use_SqlMap!_Try_it_By_Your_Self},哈哈,我没用 SqlMap。
hello_http
用 bp 抓包给重放器,改一下 http,他有几个要求,每完成一项奖励一点 flag:
用 x1cBrowser 浏览器访问。User-Agent 改为 x1cBrowser
提交 hello=world。GET 后写/?hello=world
Post 提交 web=security。Get 改为 POST,加一句Content-Type: application/x-www-form-urlencoded 后输入 web=security
从 http://localhost:8080/ 访问。写 Referer: http://localhost:8080/
从 127.0.0.1 访问。写X-Forwarded-For: 127.0.0.1
最终 http 为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /?hello=world HTTP/1.1 Host : 8.130.84.100:50002User-Agent : x1cBrowserAccept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8Cookie:flag=secret Accept-Language : zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding : gzip, deflate, brConnection : keep-aliveUpgrade-Insecure-Requests : 1Content-Length : 12Content-Type : application/x-www-form-urlencodedReferer : http://localhost:8080/X-Forwarded-For : 127.0.0.1web = security
获得 flag:0xgame{1cd6a904-725f-11ef-aafb-d4d8533ec05c}
helloz-web
虽然他说不许 F12,但还是可以用的,得到提示:
然后看看 f14g.php,访问http://8.130.84.100:50001/f14g.php,得到提示:“你知道如何查看响应包吗?”
BP 看响应包得到:æ¤ä¹flagçç¬¬äºæ®µï¼-872d-68589c4ab3d3}
拼接得到 flag:0xGame{ee7f2040-1987-4e0a-872d-68589c4ab3d3}
Reverse
BabyBase
用 IDA 打开读伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int __cdecl main (int argc, const char **argv, const char **envp) { char v4; char Str; unsigned int v6; _main(argc, argv, envp); memset (&Str, 0 , 0x40u i64); memset (&v4, 0 , 0x40u i64); puts (&::Str); scanf ("%s" , &Str); puts (&byte_405052); v6 = strlen (&Str); encode(&Str, &v4, v6); if ( v6 != 42 || check_flag(&v4) ) { printf ("Invalid!" ); exit (0 ); } printf ("Congratulation!!" ); return 0 ; }
查看 check_flag
1 2 3 4 int __fastcall check_flag (const char *a1) { return strcmp (a1, "MHhHYW1le04wd195MHVfa24wd19CNHNlNjRfRW5jMGQxbmdfdzNsbCF9" ); }
对其进行 Base64 解码得到 flag:0xGame{N0w_y0u_kn0w_B4se64_Enc0d1ng_w3ll!}
BinaryMaster
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 int __cdecl main (int argc, const char **argv, const char **envp) { BOOL v3; char Buffer; BOOL v6; _main(argc, argv, envp); puts ("Welcome to the world of Binary!" ); printf ("But, do you know \"Octal\" and \"Hexadecimal\"?" ); puts ("\n" ); puts ("This is an Oct number: 04242424" ); puts ("Please convert it to Hex:" ); gets(&Buffer); v3 = strcmp ("0x114514" , &Buffer) && strcmp ("114514" , &Buffer); v6 = v3; if ( v3 ) { puts ("try again . . ." ); system("pause" ); exit (0 ); } puts (&byte_40409A); puts ("You find it!" ); puts ("0xGame{114514cc-a3a7-4e36-8db1-5f224b776271}" ); return 0 ; }
emm,他想说 114514 转为 8 进制是 04242424,但他已经给答案了,flag:0xGame{114514cc-a3a7-4e36-8db1-5f224b776271}
SignSign
先找到后半段_b3g1n_Reversing_n0w},再往前翻翻发现,得到0xGame{S1gn1n_h3r3_4nd
flag:0xGame{S1gn1n_h3r3_4nd_b3g1n_Reversing_n0w}
Xor-Beginning
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 82 83 84 85 86 87 88 89 90 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[64 ]; char v5; char v6; char v7; char v8; char v9; char v10; char v11; char v12; char v13; char v14; char v15; char v16; char v17; char v18; char v19; char v20; char v21; char v22; char v23; char v24; char v25; char v26; char v27; char v28; char v29; char v30; char v31; char v32; char v33; char v34; int v35; int v36; _main(argc, argv, envp); v36 = 0 ; v35 = 0 ; v5 = 126 ; v6 = 53 ; v7 = 11 ; v8 = 42 ; v9 = 39 ; v10 = 44 ; v11 = 51 ; v12 = 31 ; v13 = 118 ; v14 = 55 ; v15 = 27 ; v16 = 114 ; v17 = 49 ; v18 = 30 ; v19 = 54 ; v20 = 12 ; v21 = 76 ; v22 = 68 ; v23 = 99 ; v24 = 114 ; v25 = 87 ; v26 = 73 ; v27 = 8 ; v28 = 69 ; v29 = 66 ; v30 = 1 ; v31 = 90 ; v32 = 4 ; v33 = 19 ; v34 = 76 ; printf (&Format); scanf ("%s" , v4); while ( v4[v36] ) { v4[v36] ^= 78 - (_BYTE)v36; ++v36; } while ( v35 < v36 ) { if ( v4[v35] != (unsigned __int8)*(&v5 + v35) || v36 != 30 ) { printf (asc_404022); system("pause" ); exit (0 ); } ++v35; } puts (Str); system("pause" ); return 0 ; }
先读码,v5 到 v34 应为长度为 30 的数组
代码大意是输入的 30 位字符串(即 flag)分别与 78、77、76······做异或操作与 126、53···76 比较
由于异或可逆,只要将 126、53···76 与 78、77、76······异或就能得到 flag 的 Ascii 码
这里用 python 来算
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 // Xor c = 126 ^ 78 ; printf("%c" , c); c = 53 ^ 77 ; printf("%c" , c); c = 11 ^ 76 ; printf("%c" , c); c = 42 ^ 75 ; printf("%c" , c); c = 39 ^ 74 ; printf("%c" , c); c = 44 ^ 73 ; printf("%c" , c); c = 51 ^ 72 ; printf("%c" , c); c = 31 ^ 71 ; printf("%c" , c); c = 118 ^ 70 ; printf("%c" , c); c = 55 ^ 69 ; printf("%c" , c); c = 27 ^ 68 ; printf("%c" , c); c = 114 ^ 67 ; printf("%c" , c); c = 49 ^ 66 ; printf("%c" , c); c = 30 ^ 65 ; printf("%c" , c); c = 54 ^ 64 ; printf("%c" , c); c = 12 ^ 63 ; printf("%c" , c); c = 76 ^ 62 ; printf("%c" , c); c = 68 ^ 61 ; printf("%c" , c); c = 99 ^ 60 ; printf("%c" , c); c = 114 ^ 59 ; printf("%c" , c); c = 87 ^ 58 ; printf("%c" , c); c = 73 ^ 57 ; printf("%c" , c); c = 8 ^ 56 ; printf("%c" , c); c = 69 ^ 55 ; printf("%c" , c); c = 66 ^ 54 ; printf("%c" , c); c = 1 ^ 53 ; printf("%c" , c); c = 90 ^ 52 ; printf("%c" , c); c = 4 ^ 51 ; printf("%c" , c); c = 19 ^ 50 ; printf("%c" , c); c = 76 ^ 49 ; printf("%c" , c);
哈哈,最后 10 分钟做的比较急,写的繁琐一点
最后算出 0xGame{X0r_1s_v3ry_Imp0rt4n7!}
Xor-Endian | Review
当时没来得及做完,也是异或加密
1 7B 1D 3E 51 15 22 1A 0F 56 0A 51 56 00 28 5D 54 07 4B 74 05 40 51 54 08 54 19 72 56 1D 04 55 76 56 0B 54 57 07 0B 55 73 01 4F 08 05
Key0xGame2024
1 0xGame{b38ad4c8-733d-4f8f-93d4-17f1e79a8d68}