Showing posts with label News. Show all posts
Showing posts with label News. Show all posts

Binary Exploitation

  Không có mô tả.

Tổng quan
Binary Exploitation (hay còn gọi là pwn) liên quan đến việc tìm ra lỗ hổng trong chương trình và khai thác nó để giành quyền kiểm soát hoặc sửa đổi các chức năng của chương trình. Công việc này nghiên cứu về các lỗ hổng mà phổ biến có thể kể đến như:

  • Buffer Overflow (tràn bộ đệm): Tràn bộ đệm là lỗi thông thường, dễ phòng chống, nhưng lại rất phổ biến và có hậu quả nguy hiểm nhất. Nó được xếp vào hàng danh sách các lỗi đe dọa nghiêm trọng đến sự an toàn của chương trình và hệ thống. Năm 2009, viện SANS (Escal Institute of Advanced Technologies) đã đưa ra báo cáo 25 lỗi lập trình nguy hiểm nhất trong đó có lỗi tràn bộ đệm.

  • Integer Overflow (tràn số nguyên): Tràn số nguyên xảy ra khi một phép toán số học có kết quả nằm ngoài phạm vi có thể được biểu diễn bằng một số có số chữ số nhất định (có thể là cao hơn giá trị lớn nhất hoặc thấp hơn giá trị nhỏ nhất có thể biểu diễn của kiểu dữ liệu).

  • Return Oriented Programming (ROP): Đây là một kỹ thuật khai thác bảo mật được các hacker khai thác để thực thi các đoạn mã (thường là nhằm mục đích xấu) trên hệ thống của nạn nhân.

  • Format String Vulnerable (lỗ hổng định dạng chuỗi): Xảy ra khi dữ liệu được đưa vào bị chương trình xem như một lệnh để thực thi. Bằng cách này, hacker có thể thực thi các đoạn mã, đọc ngăn xếp hoặc gây ra lỗi phân đoạn trong chương trình đang chạy, gây ra các hành vi có thể ảnh hưởng đến bảo mật hoặc sự ổn định của hệ thống.

  • Heap Exploitation: là một lỗ hổng mà xảy ra khi có nhiều dữ liệu hơn số lượng có thể chứa trong bộ đệm đã được cấp phát. Nó có thể dẫn đến hỏng siêu dữ liệu heap hoặc hỏng các đối tượng heap khác, từ đó cung cấp bề mặt tấn công mới.

Ví dụ Ở đây, mình lấy ví dụ về lỗi tràn bộ đệm, còn các lỗ hổng khác các bạn có thể tìm hiểu trên mạng để được các chuyên gia mô tả cho dễ hình dung. Quay lại buffer overflow thì như đề cập ở trên thì đây là một lỗi rất dễ phòng tránh tuy nhiên nó vẫn có thể xảy ra và dẫn đến các hậu quả hết sức nguy hiểm. Nguy hiểm thế nào thì ta sẽ bắt đầu đi vào ví dụ sau: Trường Đại học U đang triển khai đăng ký thông tin nhập học cho tân sinh viên. Sau khi nhập các thông tin cần thiết vào chương trình trên, sinh viên A nhận được một giao diện có thiết kế như sau:

Họ và tên

Số điện thoại

Điểm xét tuyển

Nguyễn Văn A

0908222227

7.3

Trong đó, mục [Họ và tên] và [Điểm xét tuyển] là Chỉ-có-thể-đọc (được bôi đậm) , còn ở [số điện thoại], sinh viên được phép sửa đổi. Yêu cầu của số điện thoại là tối đa 10 chữ số. Nhận thấy số điện thoại của mình bị sai, A thực hiện thao tác sửa đổi và cập nhật mới. Trong quá trình sửa đổi, A vô tình bấm “nhầm” thêm một số dẫn đến đầu vào là một dãy 11 chữ số như sau 09082222229. Sau khi ấn submit, kết quả mà A nhận được là

Họ và tên

Số điện thoại

Điểm xét tuyển

Nguyễn Văn A

0908222222

9.7

Đến đây thì mình tin chắc các bạn cũng đã hiểu ra vấn đề. Ở đây chữ số 9 ở số điện thoại đã bị thay thế vào vị trí của số 7 trong mục [Điểm xét tuyển] hay nói các khác là chữ số thừa này của [Số điện thoại] đã bị tràn sang bộ nhớ bên cạnh nó. Với số điểm xét tuyển gần như tuyệt đối này thì không có cớ gì A sẽ được trao học bổng trong 4 năm học ngay và luôn. Tuy nhiên, do A là một học sinh trung thực, 12 năm liền học sinh Giỏi và là cháu ngoan Bác Hồ nên A đã chủ động liên hệ với nhà trường để báo cáo lỗi. Nhờ việc xử lý và giải quyết một cách nhanh nhẹn, A đã được nhà trường tuyên dương cũng như trao thưởng. Phần thưởng tuy nhỏ nhưng A được cả trường biết đến và được nhận nhiều lời tán dương. A rất tự hào và tự hứa sẽ học tập thêm kỹ năng ATTT để tiếp tục phát hiện và báo cáo nhiều lỗi như thế nữa. Chính vì vậy, A đã đăng ký tham gia vào CLB FPTU - Ethical Hacker Club, một câu lạc bộ về ATTT mà đúng với tiêu chí của A là BDSM (Bay bổng - Đảm đang - Sáng tạo - Muôn màu) Tuy nhiên đây chỉ là một câu chuyện hoang tưởng để lấy ví dụ về Binary Exploitation, các bạn không nên làm tại nhà vì rất dễ được “học bổng” của nhà nước (được ở nhà của nhà nước, được ăn cơm nhà nước, mặc quần áo nhà nước). Trên thực tế thì buffer overflow cũng tương tự như vậy. Các lỗ hổng liên quan đến việc tràn bộ đệm thường xảy ra do lập trình viên bỏ qua các chú ý đến nguy cơ bị ghi đè dữ liệu lên các vùng nhớ kế cận. Ở phần kết luận, mình sẽ đưa ra giải pháp cho các lập trình viên newbie cách phòng tránh vấn đề này.

Kết luận

Về tác hại: các lỗi liên quan đến Binary Exploitation làm cho chương trình dừng hoạt động, gây mất dữ liệu hoặc khiến cho kẻ xấu lợi dụng để tấn công, kiểm soát hệ thống nhằm mục đích trục lợi. Để phòng tránh lỗi tràn bộ đệm ở các chương trình C, các lập trình viên nên đọc kỹ về hàm gets, nó thường được cảnh báo nguy hiểm trong khi biên dịch chương trình. Giả sử có biến var, kết quả của printf (var) sẽ là bao nhiêu nếu var là %p. Hãy thử viết một chương trình C như vậy và tự xem kết quả. Bật mí thì đây là ví dụ của lỗi định dạng chuỗi. Có một số trang để rèn luyện kỹ năng về Binary Exploitation có thể kể đến như pwnable.tw, đây là trang web hoàn toàn miễn phí. Các thử thách trên đây luôn được cập nhật để bổ sung kỹ năng cho bạn. Ngoài ra có một số trang khác như HackTheBox cũng là một nơi để các bạn bắt đầu nghiên cứu về mảng bảo mật này.
spacer

ACSC 2021 | Web Writeup | API

 

API

Thử thách:

Kiến thức nền:

  • Broken Access Control.

Giải quyết vấn đề:

1/ Thăm dò:

Như mọi dạng bài cho source code từ trước, việc đầu tiên chúng ta cần làm là tôn trọng tác giả, mở source code ra đọc và deploy nó lên. Vào trong root folder public rồi deploy trên locahost bằng lệnh php -S localhost:<any port number>. Tạm thời chưa quan tâm đến các file config như 000-default.conf, docker-compose.yml hay Dockerfile, chúng ta sẽ sử dụng sau. Nhìn sơ qua thì chúng ta có một cái web app chỉ có 3 chức năng thế này:

  • Sign in:

image

  • Sign up:

image

  • Trang admin (không hiểu sao không cần sign in cũng vào được, nhưng mà nhìn chung nó cũng vô dụng):

image

Thử tạo một account tại signup.html rồi đăng nhập vào thử:

image

2/ Nghiên cứu source code:

Bài này nhìn chung là khá dễ, nếu thậm chí nếu bạn đọc code và suy nghĩ theo cách đơn giản thì sẽ ra flag cực kì nhanh. Nhưng tôi và thằng teammate baolongv3 đã chọn cách khó hơn, đó là ăn hết tất cả cú lừa của bài này.

Cú lừa đầu tiên, không biết là vô tình hay cố ý mà tác giả lại để lộ 2 cái file "mới nhìn tưởng là quan trọng và là chìa khóa để tìm ra flag" này:

  • user.db: file chứa toàn bộ thông tin account của tất cả các user trên web app này, mỗi field thông tin khác nhau được ngăn cách bởi dấu | (theo tôi dự đoán thì nó theo format sau: username|hash của password|user level (admin sẽ được gán bằng 1, normal user được gán bằng 0)). Khi refresh trang thì ta thấy file được append thêm một số account mới. Tất cả các account này đều có user level bằng 0. Chỉ duy nhất account có username tên Pang (trong hình) có user level bằng 1.

image

Nhìn vào hàm main, ta thấy file user.db vốn không có sẵn trong folder db. Nó được khởi tạo bằng cách gọi hàm gen_user_db:

function gen_user_db($acc){
    $path = dirname(__FILE__).DIRECTORY_SEPARATOR;
    $path .= "db".DIRECTORY_SEPARATOR;
    $path .= "user.db";
    if (file_exists($path)) return false;
    else {
        global $admin;
        $u = new User($acc);
        $fmt = sprintf("%s|%s|%d,", $admin['id'], $u->gen_hash($admin['pw']), $admin['level']);
        file_put_contents($path, $fmt);
    }
}

Nếu file user.db chưa được tạo, nó sẽ được tạo mới bởi hàm file_put_contents, đồng thời hàm này sẽ ghi vào file user.db mới được tạo account của admin thông qua biến $fmt, biến này lại lấy các field id, pw và level từ global array $admin được gọi từ file config.php:

<?php
$admin = ['id' => "*secret*", 'pw' => "*secret*", 'level' => 1];
?>

Vậy là đúng như dự đoán, admin được gán level bằng 1, như vậy account có id là "Pang" chắc chắn là admin, và ta cần lấy được password của user này bằng cách dehash cái này: c307cae832059f15e52cc5e6a26a2eb3ae7173e6. Password được hash bằng hàm ripemd160:

public function gen_hash($val){
    return hash("ripemd160", $val);
}

Nhưng có vẻ đây là một challenge dùng não 100%, đừng phí thời gian chạy hashcat hàng tiếng đồng hồ để tìm password như tôi nhé, nó không ra cái gì đâu @@

  • passcode.db: chứa một string có độ dài 5 kí tự, nếu chỉ nhìn mà không đọc code kĩ thì sẽ rất dễ nhầm đây là salt mà tác giả ném vào hàm hash ripemd160 để băm password của các user. Nếu deploy đoạn code này (lấy từ hàm gen_pass_db) thì bạn sẽ đấy string này random từ biến $rand_str sau mỗi lần refresh trang:
$rand_str = "`~1234567890-=!@#$%^&*()_+qwertyuiopT[]\\";
$rand_str .= "asdfghjkl;':\"zxcvbnm./<>?QWERASDFZCVBNM";
$res = '';
for($i = 0; $i < $len; $i++){
    $res .= $rand_str[rand(0, strlen($rand_str)) - 1];
}
echo $res;

Nhưng trên url thì dù refresh lại bao nhiêu lần nó cũng ra ":<vNk". Lí do là vì file passcode.db cũng hoạt động giống file user.db, nếu file đã được tạo rồi thì hàm sẽ kết thúc và không đụng gì file nữa:

if (file_exists($path)) return false;

image

=> Xem xong file này tôi có 2 thắc mắc:

- Hai hàm gen_user_db và gen_pass_db đều hoạt động giống y hệt nhau, tại sao refresh trang user.db thì thấy các account mới được append vào còn passcode.db thì vẫn giữ nguyên như vậy? Chứng tỏ có một hàm nào đó khác nữa đã làm công việc append này, và nó chính là hàm signup (check file/2021/web/source/public/lib/User.class.php)):

public function signup(){
    if (!preg_match("/^[A-Z][0-9a-z]{3,15}$/", $this->acc[0])) return false;
    if (!preg_match("/^[A-Z][0-9A-Za-z]{8,15}$/", $this->acc[1])) return false;
    $data = $this->load_db();
    for($i = 0; $i < count($data); $i++){
        if ($data[$i][0] == $this->acc[0]) return false;
    }
    file_put_contents($this->db['path'], $this->db['fmt'], FILE_APPEND);  // $this->db['path'] == 'public/lib/db/user.db' và $this->db['fmt'] = sprintf("%s|%s|%d,", $this->acc[0], $this->gen_hash($this->acc[1]), 0) 
    return true;
}

- Nếu ":<vNk" trong file passcode.db không phải là salt của hàm hash ripedm160, vậy nó được tạo ra để làm gì? Nhìn vào hàm is_pass_correct trong file Admin.class.php/2021/web/source/public/lib/Admin.class.php), ta thấy $passcode lấy data từ file passcode.db thông qua hàm get_pass, $input lấy data từ value của parameter pas được lưu trên superglobal REQUEST, sau đó nếu 2 biến này bằng nhau thì return true:

public function is_pass_correct(){
    $passcode = $this->get_pass();  // $passcode == ':<vNk'
    $input = $_REQUEST['pas'];
    if ($input == $passcode) return true;
}

3/ Khai thác:

  • Nói thêm một chút về các parameter nằm trong superglobal REQUEST của bài này, tất cả đều được gửi từ form signin thông qua hàm signin nằm trong file client.js/2021/web/source/public/static/js/client.js). Nếu theo luồng hoạt động của hàm này thì chỉ có 3 parameter được gửi vào REQUEST là id, pw và c (1). Như vậy, để hàm is_pass_correct có thể return true, ta phải tự chèn thêm parameter pas=:<vNk vào sau khi sign in (2).
  • Như đã thấy ở phần thăm dò, dù có tạo được account thì chúng ta cũng không thể vào được bên trong, web app chỉ alert rằng "Only admin can access the page". Bắt thử một request rồi send qua repeater của Burp Suite thì ta được:

image

  • Response cho biết rằng trang web đang bị chuyển hướng đến /api.php?#access denied do đoạn code javascript location.href = '/api.php?#access denied';. Vậy đoạn code javascript này từ đâu ra. Check hàm main rồi mò lại hàm challenge, ta có:
$admin = new Admin();
if (!$admin->is_admin()) $admin->redirect('/api.php?#access denied');
$cmd = $_REQUEST['c2'];
if ($cmd) {
    switch($cmd){
        case "gu":
            echo json_encode($admin->export_users());
            break;
        case "gd":
            echo json_encode($admin->export_db($_REQUEST['db']));
            break;
        case "gp":
            echo json_encode($admin->get_pass());
            break;
        case "cf":
            echo json_encode($admin->compare_flag($_REQUEST['flag']));
            break;
    }
}
  • Đọc lướt qua thì ta sẽ thấy đây là một đoạn code authorize rất bình thường, khi account không phải admin thì sẽ trả về response như đã thấy trên Burp Suite. Nhưng nhìn kĩ lại một chút thì chúng ta phát hiện một sai lầm cực kì tai hại của người viết đoạn code này, đó chính là dùng if (!$admin->is_admin()) cho câu lệnh $admin->redirect('/api.php?#access denied'); nhưng lại quên đặt các khối lệnh phía sau vào else. Điều này đồng nghĩa rằng kể cả account của bạn không phải là admin, đăng nhập vào bị alert ra lỗi, nhưng vẫn có thể thực thi toàn bộ các lệnh ở phía sau if. Vấn đề bây giờ chỉ là chọn value nào để inject vào parameter c2 trong các value gu, gd, gp và cf. Nếu chọn gd thì ta sẽ gọi được hàm export_db, hàm này lại lấy data từ paramter db. Cùng xem hàm này hoạt động như thế nào:
public function export_db($file){
    if ($this->is_pass_correct()) {
        $path = dirname(__FILE__).DIRECTORY_SEPARATOR;
        $path .= "db".DIRECTORY_SEPARATOR;
        $path .= $file;
        $data = file_get_contents($path);
        $data = explode(',', $data);
        $arr = [];
        for($i = 0; $i < count($data); $i++){
            $arr[] = explode('|', $data[$i]);
        }
        return $arr;
    }else 
        return "The passcode does not equal with your input.";
}
  • Để hàm này có thể chạy được ta cần phải chèn vào request pas=:<vNk như đã giải thích ở cuối phần Nghiên cứu source code. Trong luồng hoạt động của hàm này chúng ta chỉ cần để ý duy nhất lệnh $data = file_get_contents($path); là có thể kết luận sử dụng hàm này ta có thể đọc được nội dung của một file bất kì trong hệ thống, trong đó có file flag. Sau khi mò được đường dẫn của flag thì ta đã có flag trong tay:

image

  • Payload: id=Baictfkhoqua&pw=Aa1234567&c=i&pas=:<vNk&c2=gd&db=../../../../../../../flag
  • Flag: ACSC{it_is_hard_to_name_a_flag..isn't_it?}
spacer

Code Battle 2019

 💢💢💢Chặng đường CodeBattle2019 đã chính thức khép lại. 💢💢💢

📍📍Ngày 05/05, tại trường đại học FPT, khu Công nghệ cao Hòa Lạc, cuộc chiến CodeBattle 2019 đã diễn ra trong không khí quyết liệt suốt 6 giờ đồng hồ giữa các đội thi từ các câu lạc bộ tin học tham gia dự thi. Chức vô địch cùng những giải thưởng giá trị của chương trình đã được trao về tay những đội xứng đáng.️🎊️🎊️🎊


Chúc mừng tất cả các đội thi đã nỗ lực hoàn thành bài thi của mình và sau đây là các đội đã vươn lên dẫn đầu của cuộc thi:

🥇EndGame (JS-FPT) - Giải nhất 

🥈Kurisutina (Đại học Công Nghệ - ĐHQGHN) - Giải nhì

🥉ITPTIT_Bé xin cái giải - Giải ba

️🏅PROPTIT_Ám Nhiên Tiêu Hồn Chưởng - Nhất nội dung AI

🏅rm -r /brain/* (JS-FPT) - Nhất nội dung ACM

🏅ITPTIT_CodeBattle_Injection - Nhất nội dung CTF

(Tất cả giải thưởng các giải sẽ được gửi cho đại diện các CLB trong tuần này)

🍀Dù ai là người chiến thắng có lẽ cũng không ý nghĩa bằng thời gian chúng ta đã có tại FPTU. Chắc hẳn các đội chơi vẫn còn những cảm xúc đáng nhớ tại ngôi trường đẹp như mơ này cùng những người bạn dễ mến đến từ các câu lạc bộ. Những giây phút căng thẳng lúc cuối giờ thi, những hình ảnh của các bạn trong ban tổ chức. Tất cả đã trở thành dấu ấn khó phai mờ của Code Battle 2019 trong kí ức các đội dự thi.❤️

🌺Code Battle năm nay đã đến hồi khép lại, đánh dấu sự hợp tác tổ chức giữa năm câu lạc bộ PROPTIT, ITPTIT, TLIT, JS FPT & HAMIC trong hiện tại và trong tương lai. Sự đoàn kết này hứa hẹn năm sau chương trình sẽ trở lại và lợi hại hơn gấp nhiều lần. Các bạn hãy cùng theo dõi và chờ đợi CodeBattle 2020 nhé.❤️

️🎈️🎈Lời cuối cùng, Ban tổ chức xin cảm ơn:

👉Toàn thể các bạn thí sinh đã đến tham dự cuộc thi!

👉Các bạn trong ban tổ chức đã nỗ lực không ngừng nghỉ để chương trình được diễn ra thành công!

👉Cảm ơn trường đại học FPT đã hỗ trợ cơ sở hạ tầng rất tốt.

👉 Đặc biệt BTC cũng xin trân thành cảm ơn các nhà tài trợ đã đồng hành cùng CodeBattle2019

- Đơn vị bảo trợ: Đoàn thanh niên Học viện Công nghệ Bưu chính Viễn thông

- Đơn vị hỗ trợ: Phòng hợp tác quốc tế và phát triển cá nhân IC-PDP

- Các nhà tài trợ Bạc:

+ Công ty cổ phần đầu tư và giải pháp VietIS

+ Tổng công ty Viễn thông Viettel - Chi nhánh tập đoàn Công nghiệp - Viễn thông Quân đội

+ Công ty TNHH Alt Plus Việt Nam

spacer