Miscellaneous - Linux


SuckMore Shell

  • Challenge: A new Command Line based UI is given (Limited shell). Could you escape the shell to read other stuff and get flag at /flag.txt

  • Recon and Trail+Error

    • Trying all basic commands,
- ls
- apt
- touch
- ps -ef
- cat
- pwd
- uname -a
- less
- more
- bash
- set
- bash
- /bin/sh -i
root@kali:~/Downloads/chirp# ssh ctf@107.21.60.114
ctf@107.21.60.114's password: 

SuckMORE shell v1.0.1. Note: for POSIX support update to v1.1.0
suckmore>

suckmore>apt
bash: apt: command not found

suckmore>ls
suckmore>ll
bash: ll: command not found

suckmore>ps -ef
bash: ps: command not found

suckmore>touch
touch: missing file operand
Try 'touch --help' for more information.

suckmore>pwd

suckmore>uname -a
Linux ad8528675a00 4.15.0-1035-aws #37-Ubuntu SMP Mon Mar 18 16:15:14 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

suckmore>bash
Why would you ever want to leave suckmore shell?
suckmore>/bin/sh

suckmore>set
BASH=/bin/sh
BASHOPTS=cmdhist:complete_fullquote:expand_aliases:extquote:force_fignore:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="4" [2]="23" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.4.23(1)-release'
COLUMNS=101
DIRSTACK=()
DISTTAG=fcontainer
EUID=1000
FBR=f
FGC=f
GROUPS=()
HISTFILE=/home/ctf/.bash_history
HISTFILESIZE=500
HISTSIZE=500
HOME=/home/ctf
HOSTNAME=ad8528675a00
HOSTTYPE=x86_64
IFS=' 	
'
LINES=38
MACHTYPE=x86_64-redhat-linux-gnu
MAILCHECK=60
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
POSIXLY_CORRECT=y
PPID=1
PS1='suckmore>'
PS2='> '
PS4='+ '
PWD=/
SHELL=/bin/sh
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor:posix
SHLVL=3
TERM=xterm
UID=1000
_=/bin/sh

suckmore>/bin/sh -i
  • Even though some commands were informative nothing was promising. The commands more and less sounded interesting and also linked to the challenge title –> more
suckmore>less
We are suckMORE, not suckless
suckmore>more
SuckMORE shell, v1.0.1, (c) SuckMore Software, a division of WPI Digital Holdings Ltd.
  • Investigating more command further to read the flag. Once the shell was upgraded with /bin/sh, more command worked in different way to escape jail and read the flag.
suckmore>more /home/ctf/flag
SuckMORE shell, v1.0.1, (c) SuckMore Software, a division of WPI Digital Holdings Ltd. /home/ctf/flag

suckmore>/bin/sh

suckmore>more
more: bad usage
Try 'more --help' for more information.

suckmore>more /home/ctf/flag
WPI{bash_sucks0194342}
suckmore>
  • References
https://pleiades.ucsc.edu/hyades/SSH_Escape_Sequences
https://netsec.ws/?p=337

PseudoRandom

Solved after the CTF ended

  • Challenge Random is not really a random.

  • Thoughts Obviously this had got to something with the randoms
    • /dev/urandom
    • /dev/random
  • Looking at /dev/urandom we get a base64 encoded string which doesnt change. Decoding this just returned some random bytes.
sh-4.4$ cat urandom 
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

  • Looking at /dev/random we get a some string with salted keyword.
sh-4.4$ cat random 
Salted__?>
          [?/?=????m?k???V?SӨ?
                              %텤'Ϊ0KIWi?Գro?ۃ?:
e???i????|?|[V?e??=a???ȽUP?R?k??l?????1|??ϕ!?L??9??%?(?K??s$?U f_??? 	?Up?%ޏ?#?Q??F?4??+??x?pc?&?-?ַ?쒓+c??њ?K??.??9?g??W??l2?`!?????>BS?G???k?de?????4?Z?2?l???$*[????S(?3m_?
?
???k????w4??`hMfbi)?H?ˠZ?!ሥ?*???Fw?Ed?aĄ???\?_???TWLBE>J??ڼ?(?"?g????0݁?@ͨ{1?oe?#??I%?O?s*?+?D{?????d??@?[?2?????F??̷&??rv	Qw?Ռ$Tz?;e?3s?????=?W??i?????YV?kϿwl??`?@(???V??&i?y??|?쩷?҃+??\q><?{K-?5??1?Y?	<?:?d54?hm
                                                   ????E3Х?sh-4.4$ 
sh-4.4$ 
  • After this step I was out of direction on what needs to be done to move forward. I spent a long time thinking this might be a crypto challenge from here on.

  • After some long time, I tried some basic recon and got some lead

sh-4.4$ 
sh-4.4$ file urandom 
urandom: ASCII text
sh-4.4$ file random 
random: openssl enc'd data with salted password
  • Using OpenSSL to use the urandom string as the key to decrypt the random string was the solution
sh-4.4$ openssl enc -aes-256-cbc -d -in random -kfile urandom
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
Being holy in our church means installing a wholly free operating system--GNU/Linux is a good choice--and not putting any non-free software on your computer. Join the Church of Emacs, and you too can be a saint!
And lo, it came to pass, that the neophyte encountered the Beplattered One and humbly posed the question "Oh great master, is it a sin to use vi?" And St. IGNUcuis dist thus reply unto him, "No, my young hacker friend, it is not a sin. It is a penance."
WPI{@11_Ur_d3v1c3s_r_b3l0ng_2_us}

Cryptography


JoCipher

A Crypto + Python Reversing challenge

  • Challenge
40


  • Reversing .pyc file to read source code
  • Filling in the arguments to check the output with the program
  • Known Plain-text method to bypass full reversing –> Try out different values until we get format WPI{}


  • Once correct format is received skipping through similar values of t to get a flag that makes sense.


  • SourceCode

# 2019.04.13 22:02:20 PDT
# Embedded file name: ./jocipher.py
import argparse, re
num = ''
first = ''
second = ''
third = ''

def setup():
    global third
    global second
    global num
    global first
    num += '1'
    num += '2'
    num += '3'
    num += '4'
    num += '5'
    num += '6'
    num += '7'
    num += '8'
    num += '9'
    num += '0'
    first += 'q'
    first += 'w'
    first += 'e'
    first += 'r'
    first += 't'
    first += 'y'
    first += 'u'
    first += 'i'
    first += 'o'
    first += 'p'
    second += 'a'
    second += 's'
    second += 'd'
    second += 'f'
    second += 'g'
    second += 'h'
    second += 'j'
    second += 'k'
    second += 'l'
    third += 'z'
    third += 'x'
    third += 'c'
    third += 'v'
    third += 'b'
    third += 'n'
    third += 'm'


def encode(string, shift):
    result = ''
    for i in range(len(string)):
        char = string.lower()[i]
        if char in num:
            new_char = num[(num.index(char) + shift) % len(num)]
            result += new_char
        elif char in first:
            new_char = first[(first.index(char) + shift) % len(first)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in second:
            new_char = second[(second.index(char) + shift) % len(second)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in third:
            new_char = third[(third.index(char) + shift) % len(third)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        else:
            result += char

    print result
    return 0


def decode(string, shift):
    result = ''
    shift = -1 * shift
    for i in range(len(string)):
        char = string.lower()[i]
        if char in num:
            new_char = num[(num.index(char) + shift) % len(num)]
            result += new_char
        elif char in first:
            new_char = first[(first.index(char) + shift) % len(first)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in second:
            new_char = second[(second.index(char) + shift) % len(second)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        elif char in third:
            new_char = third[(third.index(char) + shift) % len(third)]
            if string[i].isupper():
                result += new_char.upper()
            else:
                result += new_char
        else:
            result += char

    print result
    return 0


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--string', '-s', type=str, required=True, help='the string to encode or decode')
    parser.add_argument('--shift', '-t', type=int, required=True, help='the shift value to use')
    parser.add_argument('--encode', '-e', required=False, action='store_true', help='encode the string')
    parser.add_argument('--decode', '-d', required=False, action='store_true', help='decode the string')
    args = parser.parse_args()
    setup()
    p = re.compile('[a-zA-Z0-9\\-{}]')
    if p.match(args.string) is not None:
        if args.encode:
            ret = encode(args.string, args.shift)
        elif args.decode:
            ret = decode(args.string, args.shift)
        if ret is not 0:
            print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'
    else:
        print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'
    return


if __name__ == '__main__':
    main()
# okay decompyling jocipher.pyc 
# decompiled 1 files: 1 okay, 0 failed, 0 verify failed
# 2019.04.13 22:02:20 PDT

Pwn

Source Pt1

  • This is my first time at blind pwning, without any source or binary

  • Challenge

40


  • Brutforce input arguments (Password) with As as usual


  • At a certain point the code is visible



Recon

(Nice Category!)

Chirp

  • Given
    • An image of a bird with filename chirp.jpg
40


  • A mistook this for a forensics challenge and started investigation in a different way. ( Spent a lot of time )

  • Sitting back, we just have to redact and think what we see.
    –> Filename: chrip.jpg
    –> Picture: Bird
    –> Logo: SIEGE

  • ====> Twitter @Siege


Reverse Engineer


Strings

  • This was a very easy one as the challgen name suggested. The preliminary step in binary analsysis. Use strings to extract hardcoded strings.

Web


Web Inspect

  • n00b challenge –> Inspect website source code

getAFlag

  • Challenge - Just enter the password, login and get a flag


  • Recon - Source code analysis. Found a harcoded base64 encoded string with a message


  • The pseudocode for authentication at /auth.php (hint from the above message)


  • Bypass Authentication - Inorder to bypass authentication we need to make the passcode input == password stored in server

  • Initially thought about bruteforce, then decided to play with the source code

  • Looking at the PHP vulnerabilities
    • Eliminating…
      • Comparison bugs ( === vs == )
      • Type Juggling etc.
      • Also some timing attack stuff
    • Things that seem to be very interesting are,
      • Extract function which replaces the variable
        • https://www.w3schools.com/php/func_array_extract.asp
      • getContents might be file_get_contents in php to read the file
        • https://www.geeksforgeeks.org/php-file_get_contents-function/
  • Redacting again to Bypass authentication
    • Input is in our control already
    • Passcode - We could replace this with a GET variable declaration, but it is run through getContents which makes it a bit difficult as this should be a file on the server. ( We cannot write anything new on the server? )
      • Looking at the above reference for get Contents link –> file get contents also executes http urls.. Yay!
    • Test play code below
// # The passcode seems to be a ??? char/digit combination --> bruteforce?
// # * Strict comparison is used, so we cant use equality or comparison bugs
// # Before bruteforce ==> Lets check extract vuln --> we have to pass an array to the GET query

<?php
$passcode = "Hi\n";
echo "Welcome\n";
extract($_GET);
echo file_get_contents("auth.php");
echo $input;
if ($input) {
   if ($input === file_get_contents($passcode, false, null, 0, 4)) {
     echo "flag!\n";
   } else {
     echo "Invalid!\n";
   }
}
?>
  • Progressive Thoughts –> Looking at Extract we know that it replaces the variables. Also we know that file_get_contents will execute the http url.
    • Passcode Input: We add the variable input --> test
    • Server Passcode:
      • We overwrite the passcode variable through GET with the url we host and serve a file with the same password as Input
      • Serve http @ ip --> pass.txt --> test


  • The Setup and Action
    • Serve pass.txt with content test with Ngrok and SimpleHTTPServer
    • Make a auth request with
      • Input == test
      • Passcode == http:///pass.txt


  • Voila the flag

    • Once the input == passcode we get flag


  • I included this screen because this was returned and I thought I never got the flag. After sometime I knew that source code had the flag..