Solved very little, but no excuses for this one :)
π΅ I was listening to Alessoβs PROGRESSO VOL 2 for this CTF!
| Details | Links |
|---|---|
| CTFtime.org Event Page | https://ctftime.org/event/1285/ |
Web
strpos and substr
Can you bypass this WAF
Link - strpos and substr: web.zh3r0.cf:2222
Author - hades
Visiting the page shows us the source code:
|
|
The user GET query value is taken and checked to be a string of less than 25 characters. If the value fails the two if conditions at line 10 and 13, the value will not be turned into an MD5 hash and will be passed directly to eval in 17, thus allowing for arbitrary code execution.
A normal payload for user would usually be like '.system('id').' which results in
|
|
But because the string concatenation operator . is blacklisted by the first preg_match check in line 10, we can actually use commas instead to supply arguments to echo since it is not a regular function but a language construct. This is described in the manual page for echo, and was suggested by my teammate zeyu2001.
Manual page example:
|
|
So our current payload will be this instead: ',system('id'),'.
Letβs next break down the second check in line 13. Iβve formatted it nicely and used variables to replace nested strpos and substr calls. I did dynamic testing on a local PHP server to verify my understanding of the checks.
|
|
The if statement is overall composed of two conditions on each side of a && operator. This means that we just need to fail either condition for the whole if statement to be false so that our payload wonβt turn into a MD5 hash.
|
|
The first condition from line 9 checks for the existence of ( and ) after index 4 and index 6 of the string respectively, meaning that the PHP command word used for code execution like system ought to be less than 4 characters. But because there seemed to be no such useful command available, I assumed that this check was impossible to bypass.
So, we can move on to focus on the second condition.
|
|
The first preg_match dictates that the 2 characters before any ( occurring after index 4 cannot be alphanumeric or an underscore. Fortunately, from the echo manual page I also read that expressions can be evaluated in parentheses.
Manual page example:
|
|
This means we can modify our payload to be ',('system')('id'),' and the 2 characters before ('id') will not be alphanumeric anymore.
The second preg_match takes up to 12 characters from any ( occuring after index 4, looks for a ) in those 12 characters, and checks if the character before ) is alphanumeric, an underscore, or a single quote.
In our case, we have a single quote ' before ) in ('id') so I added a space before ). The space is represented by + when URL-encoded.
Final payload for code execution: ',('system')('id'+),'
Request:
|
|
Response:
Hello uid=33(www-data) gid=33(www-data) groups=33(www-data)
uid=33(www-data) gid=33(www-data) groups=33(www-data)<br>
Listing files with
ls showed that there was a flag file in / named FLlA4agGgg999gg.Request:
|
|
Response:
Hello FLlA4agGgg999gg
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
var<br>
However, we canβt use cat to read the file contents because c is blacklisted. The only suitable command that did not breach the payload length limit of 24 was od, which returns an octal dump of the contents of files. I found out about this from https://unix.stackexchange.com/questions/86321/how-can-i-display-the-contents-of-a-text-file-on-the-command-line.
|
|
Hello 0000000 066146 063541 062547 062547 070056 070150 005015 066146
0000020 063541 074170 027170 074164 006564 063012 060554 063147
0000040 065541 032545 005015 066146 063541 060546 062553 006464
0000060 063012 060554 063147 065541 031545 005015 066146 063541
0000100 060546 062553 006462 063012 060554 063147 065541 030545
0000120 005015 064172 071063 075460 032127 066522 070125 032137
0000140 043137 067165 030537 031463 031463 031463 031463 033463
0000160 006575 063012 060554 063147 065541 033145
0000174
0000174<br>
With guidance from this stackoverflow answer explaining how to interpret odβs output, I wrote a script to convert the octal dump back to a string. Note that byte order is swapped at line 7. I also ignored some bytes that was messing up the final flag output using line 6, but I donβt know the reason behind this.
|
|
|
|
Flag: zh3r0{W4RmUp_4_Fun_13333333337}
bxxs
Weβve made some new epic updates to our website. Could you send us some feedback on it ?
β¬οΈ link - bxxs - web.zh3r0.cf:3333
Author - ZyperX
The website has a link to
/feedback, where you can send things to the admin.
While simply submitting links does not achieve any effect, my teammate zeyu2001 discovered that you can submit arbitrary HTML that will be rendered on the adminβs side. This is proven with a simple payload like:
|
|
which redirects the admin to our Burp Collaborator server and results in a successful pingback.
My teammate lim_yj found a path
/flag that says itβs only for admins, so we probably need to steal the adminβs cookies for access to this page.
However, attempting to steal the cookie via the script with
document.cookie failed, which we later realized was because the cookie had the HttpOnly attribute. By trying to extract other information instead, my teammate zeyu2001 found out that the adminβs window.location.href value was http://0.0.0.0:8080/Secret_admin_cookie_panel.
Feedback form payload:
|
|
Adminβs request to Burp Collaborator:
|
|
Visiting /Secret_admin_cookie_panel sets us with the admin cookie.
Request:
|
|
Response:
|
|
Visiting /flag now gives us the flag.
Request:
|
|
Response:
|
|
Flag: zh3r0{{Ea5y_bx55_ri8}}
Thank you for reading!