PicoCTF 2018, part 21 through 30


Introduction

This is a continuation of the series on the PicoCTF 2018 challenges I have completed so far. You can find the previous write-up here. You can find a collection of other write-ups in this series on the home page or through the related posts below this post.

Logon150 points


The next challenge wants you to login on a dandy website without a password and get the flag. Let's see what we can do!

I made a website so now you can log on to! I don't seem to have the admin password. See if you can't get to the flag. http://2018shell.picoctf.com:37861 (link)

Upon visiting the page, I am presented a form with username and password fields. The first thing I always do is to look at the source code; nothing interesting there. There is a form, so I try injecting some SQL-i assuming that something is not filtered. I enter my favorite condition in the username field:

' OR 1 #

I leave the password field empty and press enter. Voila! I have been logged in. A little caveat though, the page shows the next unfortunate message:

No flag for you

Well darn. I figure I would check out the session information, so I view the cookies. Good hunch, as it appears. There is a cookie that contains admin=False. If only there was a way to change that to a admin=True...

document.cookie = "admin=True";

Enter the previous line in the console of the developer tools, refresh and voila! There is the flag. This website is filled with security holes...

flag: picoCTF{l0g1ns_ar3nt_r34l_a280e12c}

Reading Between The Eyes150 points


The next challenge has hidden some information in an image, let's see what we can do.

Stego-Saurus hid a message for you in this image, can you retreive it?

Without looking into it too much, I tried a couple of steganography tools to decode any data in the image. I found a tool that worked and learned that least-significant-bit steganography was used for this. I once even wrote on of these tools myself, with a proprietary format, so I couldn't use that one.

I used a nice online tool which took its sweet time to decode this big image. It resulted in the flag, though, so I'm happy!

flag: picoCTF{r34d1ng_b37w33n_7h3_by73s}

Recovering From the Snap150 points


We are presented a link to a file, animals.dd to be exact.

There used to be a bunch of animals here, what did Dr. Xernon do to them?

file animals.dd yields the following output

# animals.dd: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, root entries 512, sectors 20480 (volumes <=32 MB) , Media descriptor 0xf8, sectors/FAT 20, sectors/track 32, heads 64, serial number 0x9b664dde, unlabeled, FAT (16 bit)

At first I wanted to see if I could mount this image, however it seems as if the start of the first sector is missing. I don't think we can mount this at all, so I approach this relatively large binary with binwalk - one of my all time favorite tools I couldn't do without. If you have not heard of it, try it out!

binwalk animals.dd yields a nice result:

# DECIMAL       HEXADECIMAL     DESCRIPTION
# --------------------------------------------------------------------------------
# 39424         0x9A00          JPEG image data, JFIF standard 1.01
# 39454         0x9A1E          TIFF image data, big-endian, offset of first image directory: 8
# 672256        0xA4200         JPEG image data, JFIF standard 1.01
# 1165824       0x11CA00        JPEG image data, JFIF standard 1.01
# 1556992       0x17C200        JPEG image data, JFIF standard 1.01
# 1812992       0x1BAA00        JPEG image data, JFIF standard 1.01
# 1813022       0x1BAA1E        TIFF image data, big-endian, offset of first image directory: 8
# 2136576       0x209A00        JPEG image data, JFIF standard 1.01
# 2136606       0x209A1E        TIFF image data, big-endian, offset of first image directory: 8
# 2607616       0x27CA00        JPEG image data, JFIF standard 1.01
# 2607646       0x27CA1E        TIFF image data, big-endian, offset of first image directory: 8
# 3000832       0x2DCA00        JPEG image data, JFIF standard 1.01
# 3000862       0x2DCA1E        TIFF image data, big-endian, offset of first image directory: 8

So I guess I could extract all those files with an extra option to binwalk (one of the reasons it's one of my all time favorite tools). We specify that we want to extract all data from the binary and add .jpg to each resulting file for convenience. I know there are TIFF chunks as well, however I'm going to ignore them for now - I could always rename those specific files.

binwalk --dd=".*":.jpg animals.dd

This gives me a directory _animals.dd.extracted containing a collection of images. One of the images looks like it contains the flag, upon opening the file I indeed see the flag. Success!

flag: picoCTF{th3_5n4p_happ3n3d}

Admin Panel150 points


This challenge asks you to find a password in a pcap file, which is a TCP/IP network capture we can open in Wireshark.

We captured some traffic logging into the admin panel, can you find the password?

When opening traffic.pcap in Wireshark, we see that the traffic log isn't that big. I scroll through the list of captured packet information and see mostly HTTP request related data. There is a few requests being made, and one of which is a login request with encoded form data. When I inspect one of the chunks, I see a password=.

I then decide to export all HTTP objects using Wireshark, so that I can easily dump the data. In the dumped file named login(2) you'll find the login request, including the password (which is the flag).

cat login\(2\)
# user=admin&password=picoCTF{n0ts3cur3_9feedfbc}

flag: picoCTF{n0ts3cur3_9feedfbc}

Assembly-0150 points


This challenge mentions asm0, which is a function that returns a value. Your job is to find its return value and submit that as flag.

What does asm0(0xc9,0xb0) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/assembly-0_4_0f197369bfc00a9211504cf65ac31994.

The question is what does the call asm0(0xc9, 0xb0) return to the caller. We can deduce this from the source code, which is conveniently supplied in the question description. The source code (intro_asm_rev.S):

.intel_syntax noprefix
.bits 32

.global asm0

asm0:
    push ebp
    mov  ebp,esp
    mov  eax,DWORD PTR [ebp+0x8]
    mov  ebx,DWORD PTR [ebp+0xc]
    mov  eax,ebx
    mov  esp,ebp
    pop  ebp    
    ret

Looking at the code, this doesn't seem like a complex function to reverse. The function arguments 0xc9, 0xb0 are pushed on the stack when this function is called. The stack pointer is preserved in register ebp, argument 1 is moved into eax, argument 2 is moved into ebx.

Then silly things happen, the value previously in eax (the return value register) is overwritten with the value in ebx (argument 2), after that eax is never changed again. This means that this function simply returns the second argument is is given.

That means the flag is 0xb0

flag: 0xb0

Buffer Overflow 0150 points


This challenge describes overflowing the right buffer in a program to obtain a flag. Before downloading the source and program, I assumed this would be quite a bit of work; however it was easier than I anticipated.

Let's start off simple, can you overflow the right buffer in this program to get the flag? You can also find it in /problems/buffer-overflow-0_4_ab1efebbee9446039487c64b88d38631 on the shell server. Source.

The problem description provides a link to a program and its source code. It also tells you where you can find and execute the program, considering you need the flag.txt file with the proper contents. At first, I downloaded the source code and determined the flow:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#define FLAGSIZE_MAX 64

char flag[FLAGSIZE_MAX];

void sigsegv_handler(int sig) {
  fprintf(stderr, "%s\n", flag);
  fflush(stderr);
  exit(1);
}

void vuln(char *input){
  char buf[16];
  strcpy(buf, input);
}

int main(int argc, char **argv){

  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
    exit(0);
  }
  fgets(flag,FLAGSIZE_MAX,f);
  signal(SIGSEGV, sigsegv_handler);

  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  if (argc > 1) {
    vuln(argv[1]);
    printf("Thanks! Received: %s", argv[1]);
  }
  else
    printf("This program takes 1 argument.\n");
  return 0;
}

I will start looking at the code at the first instruction of main, following the control flow, at first. I can see that the first code in main attempts to open flag.txt in read mode - if it fails, it prints an error and exits.

If it succeeds it will read the flag from the file to the char flag[FLAGSIZE_MAX] array, with a maximum length of 64 bytes. Nothing too special here yet, because fgets will not read more data than FLAGSIZE_MAX.

After this line of code, a handler function for the segmentation fault signal (SIGSEGV) is added. When I look at the handler (sigsegv_handler) I can see it prints the flag to stderr using fprintf. To me, this was quite odd; why would you output this sensitive data to stderr. That's the source of our flag, now we just need to trigger the segmentation fault.

Reading the code further I see a few calls to getegid and setresgid, but for now I don't care about these calls. getegid will return the group ID for the calling process and setresgid is defined as:

setresgid() sets the real GID, effective GID, and saved set-group-ID of the calling process (and always modifies the filesystem GID to be the same as the effective GID), with the same restrictions for unprivileged processes.

I continue and see an if statement that checks if argc is greater than 1, implying that the process was started with command line argument. If this is the case, the vuln function is called with the first command line argument. This is where you can get the exploit, simple as it is.

The vuln function uses strcpy to copy char *input to a 16-byte char buf[16]. This is not a safe copy, considering strcpy will keep on copying characters until a NUL byte is encountered. Considering buf[16] will only hold 16 char values, we can easily overflow this buffer by providing a command line argument that is longer than 16 characters.

This will cause the segmentation fault and, there is a handler for that which will dump the flag to stderr. Well then, let's go! I connect to the shell server over SSH and execute the following sequence:

cd /problems/buffer-overflow-0_4_ab1efebbee9446039487c64b88d38631
# a nice big overflow 
./vuln AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJ
# > picoCTF{ov3rfl0ws_ar3nt_that_bad_b49d36d2}

flag: picoCTF{ov3rfl0ws_ar3nt_that_bad_b49d36d2}

Caesar Cipher 1150 points


This challenge asks us to decrypt a message, the file path of the message and the title are a spoiler; it's encoded using a caesar cipher.

This is one of the older ciphers in the books, can you decrypt the message? You can find the ciphertext in /problems/caesar-cipher-1_2_73ab1c3e92ea50396ad143ca48039b86 on the shell server.

The contents of the message file:

picoCTF{payzgmuujurjigkygxiovnkxlcgihubb}

This can be brute-forced quite easily, by simply applying a Caesar rotation for every single letter in the alphabet. I created a simple script for this that shows these results, so you can quickly find the right one. This is not a perfect Caesar Cipher implementation, but merely a helper function that helps the brute-force process. The code below executes quickly.

# verbose version
# def caesar(s, r, t = 0x61):
#     bytes = [ord(c)         for c in s]         # convert to list of bytes
#     norm  = [b - t          for b in bytes]     # convert to alphabet offset
#     caes  = [(n + r) % 26   for n in norm]      # rotate!
#     chars = [chr(c + t)     for c in caes]      # convert back to char
#
#     return "".join(chars)

'''
    caesar encodes/decodes string 's' by rotating each character by
    'r' positions using character type 't' (0x61 for lower case, 0x41 for upper)
'''
def caesar(s, r, t = 0x61):
    return "".join([chr(t + (((ord(c) - t) + r) % 26)) for c in s])

# from the input: picoCTF{payzgmuujurjigkygxiovnkxlcgihubb}
content = "payzgmuujurjigkygxiovnkxlcgihubb"

# for every rotation
for rotation in range(1, 27):
    print("rot {:d}: {:s}".format(rotation, caesar(content, rotation)))

The python script finds the right rotation to be 20, resulting in justagoodoldcaesarcipherfwacbovv

flag: picoCTF{justagoodoldcaesarcipherfwacbovv}

environ150 points


This challenge asks you to find the flag in the environment variables.

Sometimes you have to configure environment variables before executing a program. Can you find the flag we've hidden in an environment variable on the shell server?

This one should be extremely easy, if the flag is simply in one of the environment variables. When logged in on the shell (I use ssh for this), simply invoke the env command. One of the variables it outputs:

SECRET_FLAG=picoCTF{eNv1r0nM3nT_v4r14Bl3_fL4g_3758492}

Well then... I don't think this fits in this range of points, I believe it is very elaborate in the description and should be one of the problems in the beginning of this CTF.

flag: picoCTF{eNv1r0nM3nT_v4r14Bl3_fL4g_3758492}

Hertz150 points


This challenge asks you to connect to the ctf server and decrypt the message you find there. The description implies that a substitution cipher was used. The title implies something about frequency, perhaps detecting character frequency is key in this challenge.

Here's another simple cipher for you where we made a bunch of substitutions. Can you decrypt it? Connect with nc 2018shell.picoctf.com 43324.

At first I was wondering if I could brute-force this problem in Python reasonably fast. Even though it seems like there is a way by analyzing patterns of words in the English language (using a word list), I figured that I simply use an existing brute-force tool for this.

There is a very capable and fast tool for doing this. I jammed the text in that tool, ensured the language was set to 'English' (assumption) and clicked 'Break Cipher'. Not all text was deciphered completely, however the sentence which contains the flag was.

This challenge was interesting in the way that it moved me to try and decipher the ciphertext myself using a programming language, I might still try to do that in the future.

flag: substitution_ciphers_are_solvable_bwpaweafci

Hex Editor150 points


This challenge implies that a picture of a cat has a secret to 'teach' you, implying the use of a hex editor is required.

This cat has a secret to teach you. You can also find the file in /problems/hex-editor_0_8c20f979e6b2740dee597871ff1a74ee on the shell server.

Immediately after downloading the hex_editor.jpg file linked to as cat I ran strings hex_editor.jpg. Now, the result shows a lot of strings with the flag at the end. I don't quite understand why a hex view should be required here, but for completeness I ran xxd hex_editor.jpg too. Obviously I still see the flag at the end of the file.

strings hex_editor.jpg | grep picoCTF
# Your flag is: "picoCTF{and_thats_how_u_edit_hex_kittos_3E03e57d}"

flag: picoCTF{and_thats_how_u_edit_hex_kittos_3E03e57d}


Related articles