Arabs Security Cyber Wargames
This CTF I joined with my team champions and scored rank 22nd
Team members:
- Mohamed Saleh
- Hussein Elsayed
- Abanob Medhat
- Waleed Negm
Enjoy the write-ups :D
"title": "promotion"
"level": 1
"description": "Find a way to promote yourself."
"points": 300
Once I opened the challenge, I found this page.
I ran directory brute force scan while investigating the website
./dirsearch.py dir -t 10 -u http://35.238.219.24/Promotion/ -e=php,elf,sh,bak,bak1,BAK,html,zip,rar,gz,log
I checked the source of the page, found nothing important
So I checked the request and response
Here's something to look at, I found a jwt token in cookies
auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoidXNlciJ9.j4ufWJ8PebEKIi5R7HSxu4s0cxucJYQivWfuQJ0ijTY
Let's see what it hiddes using https://jwt.io/
As you see the algorithm used in the token is HS256 and the data inside it {role:user}
We didn't have the signature so We tried to bypass it with couple ways I'll try to mention them in brief:
- changing the algorithm value to "none" and role to "admin" removing the sigature part from jwt so It'll look like that.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4ifQ. - Brute force the signature secret key value .
None of them worked, I tried to look for any other bypass but found none.
I returned to the brute force result, and found somethings that may be interesting
I checked them all and here's what I got:
- /.ssh/ and /vendors/ directories require authorization to access, I tried to bypass the authorization with removing the cookie or changing the request method but none worked
- most of the files inside /vendor/ directory are empty or worthless
- /login.php doesn't have any content before redirecting and seems to need an authorization to access too
- The one only thing that got me interested is /composer.lock it had the name and version of the software encrypting and decrypting the jwt token
I searched for any vulnerabilities for it but seemed to be up to date and didn't find any known vulnerabilities..
That's the point where I got stuck, I asked organizers for hint and they told me to look at the Accept header which its value was more than normal to me at first..
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
I spent a lot of time thinking about what would it be till I noticed xhtml xml xml..
It's XML External Entity!!
I found this part hard to notice without the hint what makes this challenge deserved more points
I tried some payloads and one of them worked.
I don't know the path to the web server directory, It was not the default /var/www/html/Promotion/ so I used another payload to read the index.php file.
I decrypted it and found the signature secret key W3lc0me_T0_Ar@b_S3cur1ty_Cyber_W@r_G@me
Now it's time to get admin's cookies, going back to jwt.io and encrypting the key again after changing the role to admin and setting the signature secret key to the one we found
and we got it: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4ifQ.2mlLS1yk38AxRHTLhPxJWgPgESUDk40kjg1z9oi3qec
Now let's change the auth cookie value and go to see other directories and files we couldn't access before
/vendors/ and /.ssh/ were still unauthorized but /login.php gave us a login form
I used the same XXE payload to get the login.php source code and found that it makes SQL query with the username and password and apply some filters for them
It's obvious we're going to make sql injection.
But to bypass this filter there's some points to take in consideration:
- the filter uses preg_replace() to remove specified strings.
- the space can be replaced with tab which we'll write as %09.
- the multi character strings can be bypassed by spliting them by itself or other string that's going to be removed after it e.g. (admadminin, passwo-rd).
First I tried to bypass the login and using this payload adm-in')%09o-r%091=1#
I got welcome admin message.
As you see there's no reflected value, It's blind SQL injection..
Sending the request to intruder and preparing to brute force to get the length of the password
Payload used : adm-in')%09an-d%09CHAR_LENGTH(passwo-rd)=§1§#
Payload values : numbers 1-100
The length is: 26
Another brute force to get the the password value with this payload adm-in')%09an-d%09SUBSTR(passwo-rd,§1§,1)='§1§'#
the first variable: iterating from 1 to 26
the second variable: characters from a-z,numbers 0-9, special caracters !@#$%^&*(){}[]_-+=
The Password: ascwg{cr4ck!ng_!$_pa1nful}
Despite we got the password, But the letters case was wrong
So I made another brute force to get the right case by comparing the ascii number maybe there was another better way but I didn't have time to think of another thing as the competetion was about to end
payload: adm-in')%09an-d%09ASCII(SUBSTR(passwo-rd,§1§,1))>=97#
this means return true if the letter is lowercase
The password: ASCWG{Cr4cK!nG_!$_Pa1nful}
Big credits to My teammate Abanob Medhat who cooperated with me in solving this challenge.
And special thanks to the organizer Mohamed Bahaa who helped us to get through this challenge.
"title": "Translator"
"level": 2
"description": "The only way to patch a vulnerability is by exposing it first so, Will you can Translator ?."
"points": 600
I went to the website and made directory brute force scan, Checked the source code.. nothing seems to be important.
I checked the request and response, but still nothing important
I returned to see what the directory brute force found and it got two paths that shined with some hope to find something important.
Both directories gave 403 unauthorized response
At least maybe another brute force on them could reveal something.. and yes it did.
We found a zip file inside backup directory.
Downloaded the file and tried to unzip it but it requires password, peace of cake.
Running a small program to brute force the password was enough
fcrackzip -v -u -D -p rockyou.txt backup.zip
The password: kaylaanne
Unzipped the file and it contained the source code of the index.php page.
<?php
function encryptString($plaintext, $password) {
//This is s3cr3t
}
function decryptString($ciphertext, $password) {
$ciphertext = base64_decode($ciphertext);
if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}
//$EncString = encryptString("aaaaaaaaaaaaaaaaaaaaa", "vmUeu7D9bzE5JmNE"); output:SElIT1dBUkVZT1VCUk8hIdk8ZHn/lvhO9Vammhqvg8N6OlV2KOX3uRiQ7gsn8ZXuvE4UUPOK9Q4ZhufvCiyXhAIdJxY+22Rt5AgkVy0CDcI=
class ReadListLogs
{
private $FileName = "/var/log/httpd/access_log";
private $RowNumber = 1;
public function __construct()
{
echo "__construct";
$this->ReadSave($this->FileName, $this->RowNumber);
}
public function __wakeup()
{
$this->ReadSave($this->FileName, $this->RowNumber);
}
function ReadSave($FileName,$RowNumber)
{
$this->FileName = $FileName;
$this->RowNumber = $RowNumber;
$array = explode("\n", file_get_contents($FileName));
$reversed = array_reverse($array);
$File_Contnet = $reversed[$RowNumber];
$stringxx = bin2hex(random_bytes(18));
file_put_contents(__DIR__.'/logs/'.$stringxx.".txt", $File_Contnet);
echo "End $stringxx";
}
}
$data = json_decode(file_get_contents('php://input'));
$DecryptVal = strval(decryptString($data->user,"vmUeu7D9bzE5JmNE"));
unserialize($DecryptVal);
?>
Taking a look at what the code do:
- Unreaveled encryption function that takes plain text and key
- Revealed decrypting function that takes cipher text and key
- A sample of the encrypting
After them there's a class which contains:
- Two variables $FileName and $RowNumber
- __construct and __wakeup php magic methods, these are method that run without calling them when some action happens you can read about them 





















