Posts

  1. Autoruns Bypasses


    Autoruns is a tool that is part of the Microsoft Sysinternals suite. It comes in permutations of console/GUI and 32/64 bit versions. Its main purpose is to detect programs, scripts, and other items that run either periodically or at login. It's a fantastic tool for blue teams to find persistent execution, but it is not perfect! By default, autoruns hides entries that are considered "Windows" entries (Options menu -> Hide Windows Entries). There is a checkbox to unhide them, but it introduces a lot of noise. In my preparations to red team for the Information Security Talent Search (ISTS) at RIT and the Mid-Atlantic Collegiate Cyber Defense Comptition (MACCDC) this year I found a few ways to hide myself among the Windows entries reported in Autoruns.

    For some prior work done in this area check out Huntress Labs's research and Conscious Hacker's research.

    ...


    Check out the full post for more details!
  2. Uberconference Hidden Hangup Button


    I was on an uberconference call the other day and the leader of the conference mentioned how they had the ability to disconnect anyone on the call with a "Hangup" button next to the mute and profile buttons. Looking at the interface a caller with the icons expanded looks like this:

    caller interface

    Now let's inspect... Going down to where the profile and mute buttons are located it looks like there's one more, hidden button available:

    hangup hidden html

    Removing the style="display: none;" attribute from the div causes the button to show...

    hangup enabled

    It's funny because it actually works. If you click it the person gets booted from the call, even if you aren't an admin/call leader. Web is hard.
    Thanks for reading.

  3. Hack Fortress 2019 - helloworld2.apk


    Final Score

    Another great year of Hack Fortress at Shmoocon!
    I wanted to do a post on this challenge in particular becuase it was one of two 300 point challenges on the board. I always get inside my own head about these challenges but I remind myself: they are not normal CTF challenges. These challenges are meant to be solved in just a few minutes, since the board is pretty big and the length of the competition is pretty short (30 min for prelims, 45 min for finals).

    I always focus on the Data Exploitation challenges because they usually have high point values and consist of android application reversing, basic binary reversing, macOS and image forensics (thanks Sarah), obscure encoding, crypto (sometimes), and hardware, among other things. It's a very diverse but fun category. I solved three challenges totalling 525 points in this category in the finals. This particular challenge was the majority of those points, but actually took the least time since I've had experience with android application reverse engineering before.

    The challenge details were:

    Name: HelloWorld2
    Location: helloworld2.apk
    Points: 300
    Desc: Find the encryption key
    

    Whenever I get an APK I do two things:

    Unfortunately my version of dex2jar was out of date so I had some issues with my automated decompilation tools. I ended up downloading the newest version of dextools, running dex2jar, loading the jar into JD-GUI, and exporting the sources.
    Android apps always start with MainActivity, which was in the class path fortress/hack/helloworld2. The decompiled code is below.

    package fortress.hack.helloworld2;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Base64;
    import android.view.View;
    import android.widget.EditText;
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class MainActivity
      extends AppCompatActivity
    {
      static
      {
        System.loadLibrary("native-lib");
      }
    
      public static String encrypt(String paramString1, String paramString2, String paramString3)
      {
        try
        {
          IvParameterSpec localIvParameterSpec = new javax/crypto/spec/IvParameterSpec;
          localIvParameterSpec.(paramString2.getBytes("UTF-8"));
          paramString2 = new javax/crypto/spec/SecretKeySpec;
          paramString2.(paramString1.getBytes("UTF-8"), "AES");
          paramString1 = Cipher.getInstance("AES/CBC/PKCS5PADDING");
          paramString1.init(1, paramString2, localIvParameterSpec);
          paramString1 = Base64.encodeToString(paramString1.doFinal(paramString3.getBytes()), 0);
          return paramString1;
        }
        catch (Exception paramString1)
        {
          paramString1.printStackTrace();
        }
        return null;
      }
    
      public void enceyptData(View paramView)
      {
        paramView = (EditText)findViewById(2131165238);
        ((EditText)findViewById(2131165239)).setText(encrypt(keyFromJNI(), getString(2131427370), paramView.getText().toString()));
      }
    
      public native String keyFromJNI();
    
      protected void onCreate(Bundle paramBundle)
      {
        super.onCreate(paramBundle);
        setContentView(2131296284);
      }
    }
    

    We are looking for the encryption key. In the encrypt function the first paramter passed is the key. We know this because the first parameter to the init function of javax.crypto.spec.SecretKeySpec is the key as bytes. Encrypt is called from MainActivity.enceyptData (sic) and the first parameter is keyFromJNI(). The function keyFromJNI has the prototype public native String keyFromJNI(); which means that there is a native library in the application that will provide the key back to the java app.
    Native libraries for an android application can be found in the lib directory of the APK. The unpacked apk shows four different architectures in the lib directory: arm64-v8a, armeabi-v7a, x86, and x86_64. I chose to look at the x86 version of libnative-lib.so, since Hopper is better at x86 than other architectures (in my opinion).
    Since I have reverse engineered java native libraries before I know to look for the function name and/or class name in the function list. Pictured below is both the search and the decompiled function.

    Hopper

    Looks like the classic "build a string as integers" trick. I'm assuming sub_61a0 is some kind of memory allocation function, and arg0 is always the JNIEnv pointer, which contains a bunch of useful functions to convert C types into java types to return. I'm guessing the arg0+0x29c is either NewString or NewStringUTF. Moving forward I just took all of the hex bytes from the four integers that get put into the key buffer and unhexlified them.

    In [26]: from binascii import unhexlify as unhex
    
    In [27]: unhex("212b2b636f74746f47756f596563694e")
    Out[27]: b'!++cottoGuoYeciN'
    

    Looks promising, but backwards...

    In [28]: unhex("212b2b636f74746f47756f596563694e")[::-1]
    Out[28]: b'NiceYouGottoc++!
    

    And there's the flag!
    NiceYouGottoc++

  4. sqlalchemy Magic


    I was writing a plugin for CTFd and I was faced with an interesting problem: how the hell do I add a column (attribue) to a parent table without modifying that table (or model object)???
    I was trying to assign an extra attribute to the Teams model; a one-to-many relationship between bracket and team so I could have Teams.chal_bracket and Bracket.teams, but again without modifying the Teams model.
    I had actually tried overriding the Teams model and also adding a row on the fly, but neither of those worked. I ended up with the solution below: ...


    Check out the full post for more details!
  5. Server Side Google Analytics


    I stitched together a bunch of posts from different sites to get a working setup for server-side google analytics with unique user tracking. This allows you to have a completely static (javascript-free) site and still get useful analytics data.

    server {
        # all of your other config...
            userid         on;
            userid_name    uid;
            userid_domain  <<the domain you are using this on>>;
            userid_path    /;
            userid_expires 365d;
            userid_p3p     'policyref="/w3c/p3p.xml", CP="CUR ADM OUR NOR STA NID"';
    
            location / {
                    try_files $uri $uri/;
                    index index.html;
                    post_action @analytics;
            }
    
            location @analytics {
                    internal;
                    set $ipaddr $remote_addr;
                    resolver 8.8.8.8 ipv6=off;
                    proxy_pass https://ssl.google-analytics.com/collect?v=1&tid=<<your analytics UA- tag>>&cid=$uid_got&t=pageview&dh=$host&dp=$uri&dr=$http_referer&uip=$remote_addr;
            }
    }
    
    

    Of course replace the <<the domain you are using this on>> and <<your analytics UA- tag>> with the appropriate data.
    This will result in the server sending out a GET request with the client's info to the tracking URL for each page visit. It increases bandwidth used by your server but is a neat trick regardless.

  6. Upgrading an Amazon EC2 Instance from Ubuntu Trusty to Xenial


    I had a bad time.
    I ran a do-release-upgrade on one of my Amazon EC2 instances to try and upgrade it from 14.04 (Trusty) to 16.04 (Xenial). After the update and a reboot the box refused to come back up. When I detached the drive and attached it to another to check syslog I found this:

    /sbin/dhclient -1 -v -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0
    Usage: dhclient [-4|-6] [-SNTP1dvrx] [-nw] [-p <port>] [-D LL|LLT]
                 [-s server-addr] [-cf config-file] [-lf lease-file]
                 [-pf pid-file] [--no-pid] [-e VAR=val]
                 [-sf script-file] [interface]
    Failed to bring up eth0.
    

    Oh good, it forgot how to eth0.
    I spent about four hours figuring out how to fix it:

    apt update
    apt -y upgrade
    cat  << EOF > /etc/update-manager/release-upgrades.d/unauth.cfg
    [Distro]
    AllowUnauthenticated=yes
    EOF
    apt install -y network-manager
    do-release-upgrade
    apt update
    apt -y upgrade
    systemctl enable systemd-networkd
    systemctl enable systemd-resolved
    dpkg-reconfigure resolvconf
    apt-get -y autoremove
    rm /etc/update-manager/release-upgrades.d/unauth.cfg
    reboot
    
    1. Make sure you are up to date first.
    2. Some packages (python3) complain that they are unauthenticated. Feel free to skip this if you want.
    3. Install the network-manager
    4. Leap of faith... do the upgrade
    5. Finish the upgrade by installing the rest of the packages.
    6. Enable the systemd network daemon and resolver daemon
    7. Reconfigure resolvconf so you can dns
    8. Get rid of the unauth.cfg file you created
    9. Reboot and pray.

    Thanks to these three links for the solutions (I just put them together):
    - https://askubuntu.com/a/426121
    - https://askubuntu.com/a/769239
    - http://willhaley.com/blog/resolvconf-dns-issue-after-ubuntu-xenial-upgrade/

  7. Scheduling Callbacks with WMI in C++


    I am going to be starting a series of posts on what I have learned on Windows pentesting and post exploitation. These posts will have a heavy focus on red teaming for competitions and cyber exercises. I am not a pentester, but I think some of the places to hide in Windows are cool so I want to write about them. These posts will include code snippets in powershell and C++. Much of this code I had to figure out how to write using the MSDN docs alone and feel that it is useful to put on the internet somewhere so others don't have to go through so much hassle to make it work.

    The topic of this post is scheduling persistent callbacks with Windows Management Instrumentation (WMI).

    WMI Explained (in brief)

    Essentially, WMI is an interface for configuration and information gathering on Windows systems. It is installed by default on Windows ME and up, which makes it a valuable resource for sysadmins and attackers. It contains information about all aspects of the system including processes, attached devices, and (I'm not kidding) games registered with Windows (wmic /namespace:\\root\cimv2\applications\games PATH game get). There is a lot of information here which will not be covered in this post. Exploration of what more WMI has to offer is left as an exercise to the reader!

    The interface consists of namespaces, classes, and instances of classes. Namespaces contain different classes and instances are instances of classes in a namespace. Think of a namespace as a database, a class as a table schema, and an instance as a row in that table. Instances can have properties and callable methods. One of the standard examples of method calling in WMI is creating a process with the WMI command line interface command wmic:

    wmic process call create calc.exe
    

    The above line will spawn calc.exe as the current user. ...


    Check out the full post for more details!
  8. A Better Way to Work with Raw Data Types in Python


    Working with raw data in any language can be a pain. If you are a developer there are many solutions to make it easier such as Google's Protocol Buffers. If you are a reverse engineer these methods can be too bulky especially if you are trying to quickly script an exploit (perhaps in a CTF where time is constrained). Python has always been my go-to language for exploit dev and general script writing but working with raw datatypes using just pack and unpack from the struct module is annoying and leaves much to be desired. I'm here to tell you that if you are still using pack and unpack for complex datatypes there is a better way.

    For the sake of this post we will attempt to work with the raw datatypes below defined as a C structures:

    typedef struct __attribute__((packed)) NestedStruct_ {
        unsigned char flags[3];
        uint8_t val1;
        uint8_t val2;
    } NestedStruct;
    
    typedef struct __attribute__((packed)) ExampleNetworkPacket_ {
        uint16_t version;
        uint16_t reserved;
        uint32_t sanity;
        NestedStruct ns;
        uint32_t datalen;
        unsigned char data[0];
    } ExampleNetworkPacket;
    

    The total size of the ExampleNetworkPacket structure will be 17 bytes plus any data appended on it.

    As a side note I just recently learned that the last element of the ExampleNetworkPacket is valid C and is useful to be a pointer to the end of the structure instead of having to do this:

    unsigned char data = (unsigned char*)(examplenetworkpacketptr + sizeof(ExampleNetworkPacket));
    

    Neat.
    ...


    Check out the full post for more details!
  9. Python for Hackers


    This is getting posted a bit late, but here is a presentation I gave remote for RIT's Competitive Cybersecurity Club Conference (RC4) 2016 on python tricks for hackers. It's a collection of things that I often use within python that make writing functional tools easier.

  10. MMACTF 2016 - Greeting


    Challenge description:

    Pwn
    Host : pwn2.chal.ctf.westerns.tokyo
    Port : 16317

    Reversing and Finding the Bug

    Reversing with radare2:

    Looks like another textbook format string vulnerability because the user buffer is put into sprintf and then straight into printf. This time I had to actually do the work of getting code execution because the flag was not loaded onto the stack.

    Running the binary

    I wanted to see the bug in action so I loaded up my Ubuntu VM using vagrant and checked it out:

    → ./greeting
    Hello, I'm nao!
    Please tell me your name... %08x
    Nice to meet you, 080487d0 :)
    

    Neat. Now for exploitation.

    Background

    For information on printf and a more basic format string exploit, check out the post I did on the judgement pwn challenge also from this CTF. In addition to having positional arguments, printf also has a cool feature where you can write the number of bytes that have been printed so far to a variable. This feature is what makes format string vulnerabilities so dangerous. If you can exploit one, you can get arbitrary write.

    Passing %hn to printf in the format string will write up to a half word value of the number of characters written so far. Combining this with positional arguments allows for half a word at a time to be written to anywhere. So this is bad.

    If you are interested in learning more about how format string vulnerabilities work then check out this paper

    Exploitation

    I decided to use libformatstr for this because I have never used it before and it seemed useful so I didn't have to craft the buffer manually.

    The payload function takes two arguments: an argument number and a padding number. The offset number is the word distance in memory away from your input and the padding is the number of bytes your input needs to be padded for the addresses you enter to be word aligned. Libformatstr can be used to determine these numbers:

    from pwn import *
    from libformatstr import *
    
    e = ELF("./greeting")
    r = process(e.path)
    
    r.sendline(make_pattern(0x40))
    r.recvuntil("you, ")
    res = r.recv()
    print(res)
    argnum, padding = guess_argnum(res, 0x40)
    log.info("argnum: {}, padding: {}".format(argnum, padding))
    

    Running this resulted in an output of argnum: 12, padding: 2. There was one other bit that needed to be changed as well. Since "Nice to meet you, " was being prepended to my input I had to set an additional argument when setting up the format string exploit called start_num.

    Armed with the argument number, padding, and start number I was ready to try and overwrite some values. The issue I ran into was that there are no function calls after the call to printf in main. I though of trying to overwrite a destructor (dtors), but there were none. I came across a way to overwrite the fini section of a binary to execute a function when the program was supposed to be quitting. I could not find much documentation on exactly what I needed to overwrite to make this work so I just used objdump and grep to find the symbols with fini in the name:

    → objdump -t greeting | grep fini
    08048780 l    d  .fini  00000000              .fini
    08049934 l    d  .fini_array    00000000              .fini_array
    08049934 l     O .fini_array    00000000              __do_global_dtors_aux_fini_array_entry
    08048740 g     F .text  00000002              __libc_csu_fini
    08048780 g     F .fini  00000000              _fini
    

    Five choices. Through trial and error I determined that overwriting whatever was at __do_global_dtors_aux_fini_array_entry gave me control of the program.

    My plan of attack became the following:
    1. Overwrite __do_global_dtors_aux_fini_array_entry with main
    2. Overwrite the GOT entry for strlen with system
    3. Write the full format string line into the program
    4. When main executes the second time, write /bin/sh so that the call to strlen in the getnline function executes system("/bin/sh") and gives me a shell!

    I wrote the following script to do the above:

    Running it resulted in the flag :)

    → python greet2.py REMOTE
    [*] '/home/vagrant/CTF/tokyo/greeting'
        Arch:     i386-32-little
        RELRO:    No RELRO
        Stack:    Canary found
        NX:       NX enabled
        PIE:      No PIE
    [x] Opening connection to pwn2.chal.ctf.westerns.tokyo on port 16317
    [x] Opening connection to pwn2.chal.ctf.westerns.tokyo on port 16317: Trying 40.74.112.206
    [+] Opening connection to pwn2.chal.ctf.westerns.tokyo on port 16317: Done
    [+] Wrote system onto strlen and main onto fini... trying shell
    [+] got shell
    [+] Flag: TWCTF{51mpl3_FSB_r3wr173_4nyw4r3}
    [*] Closed connection to pwn2.chal.ctf.westerns.tokyo port 16317
    

    W00t!
    TWCTF{51mpl3_FSB_r3wr173_4nyw4r3}