Jakarta writeup

原题链接:Jakarta

OVERVIEW
    - A firmware update further rejects passwords which are too long.
    - This lock is attached the the LockIT Pro HSM-1.

相较于上一题[[Santa cruz write up]],本题进一步增加了密码长度的校验,同时和[[Santa cruz write up]]一样,需要同时输入用户名和密码来解锁。

Jakarta source code

浏览代码,可以看到一如既往的,main函数还是直接调用了login函数:

4438 <main>
4438:  3150 18fc      add   #0xfc18, sp
443c:  b012 6045      call  #0x4560 <login>
4440:  0f43           clr   r15

Login

Login函数很长,

4560 <login>
4560:  0b12           push  r11
4562:  3150 deff      add   #0xffde, sp ;创建堆栈 大小为22
4566:  3f40 8244      mov   #0x4482 "Authentication requires a username and password.", r15
456a:  b012 c846      call  #0x46c8 <puts> ;//输出提示字
456e:  3f40 b344      mov   #0x44b3 "Your username and password together may be no more than 32 characters.", r15
4572:  b012 c846      call  #0x46c8 <puts>  ;//输出提示字
4576:  3f40 fa44      mov   #0x44fa "Please enter your username:", r15
457a:  b012 c846      call  #0x46c8 <puts> ;//输出提示字
457e:  3e40 ff00      mov   #0xff, r14
4582:  3f40 0224      mov   #0x2402, r15
4586:  b012 b846      call  #0x46b8 <getsn>
458a:  3f40 0224      mov   #0x2402, r15
458e:  b012 c846      call  #0x46c8 <puts>
4592:  3f40 0124      mov   #0x2401, r15
4596:  1f53           inc   r15
4598:  cf93 0000      tst.b 0x0(r15)
459c:  fc23           jnz   $-0x6 <login+0x36>
459e:  0b4f           mov   r15, r11
45a0:  3b80 0224      sub   #0x2402, r11
45a4:  3e40 0224      mov   #0x2402, r14
45a8:  0f41           mov   sp, r15
45aa:  b012 f446      call  #0x46f4 <strcpy>
45ae:  7b90 2100      cmp.b #0x21, r11
45b2:  0628           jnc   $+0xe <login+0x60>
45b4:  1f42 0024      mov   &0x2400, r15
45b8:  b012 c846      call  #0x46c8 <puts>
45bc:  3040 4244      br    #0x4442 <__stop_progExec__>
45c0:  3f40 1645      mov   #0x4516 "Please enter your password:", r15
45c4:  b012 c846      call  #0x46c8 <puts>
45c8:  3e40 1f00      mov   #0x1f, r14
45cc:  0e8b           sub   r11, r14
45ce:  3ef0 ff01      and   #0x1ff, r14
45d2:  3f40 0224      mov   #0x2402, r15
45d6:  b012 b846      call  #0x46b8 <getsn>
45da:  3f40 0224      mov   #0x2402, r15
45de:  b012 c846      call  #0x46c8 <puts>
45e2:  3e40 0224      mov   #0x2402, r14
45e6:  0f41           mov   sp, r15
45e8:  0f5b           add   r11, r15
45ea:  b012 f446      call  #0x46f4 <strcpy>
45ee:  3f40 0124      mov   #0x2401, r15
45f2:  1f53           inc   r15
45f4:  cf93 0000      tst.b 0x0(r15)
45f8:  fc23           jnz   $-0x6 <login+0x92>
45fa:  3f80 0224      sub   #0x2402, r15
45fe:  0f5b           add   r11, r15
4600:  7f90 2100      cmp.b #0x21, r15
4604:  0628           jnc   $+0xe <login+0xb2>
4606:  1f42 0024      mov   &0x2400, r15
460a:  b012 c846      call  #0x46c8 <puts>
460e:  3040 4244      br    #0x4442 <__stop_progExec__>
4612:  0f41           mov   sp, r15
4614:  b012 5844      call  #0x4458 <test_username_and_password_valid>
4618:  0f93           tst   r15
461a:  0524           jz    $+0xc <login+0xc6>
461c:  b012 4c44      call  #0x444c <unlock_door>
4620:  3f40 3245      mov   #0x4532 "Access granted.", r15
4624:  023c           jmp   $+0x6 <login+0xca>
4626:  3f40 4245      mov   #0x4542 "That password is not correct.", r15
462a:  b012 c846      call  #0x46c8 <puts>
462e:  3150 2200      add   #0x22, sp
4632:  3b41           pop   r11
4634:  3041           ret

总体汇编代码比较长,我们分段来看:

  1. 输入username以及username从堆空间到栈空间的拷贝:
# void getsn(char(*)(0x2402), 0xff);
457e:  3e40 ff00      mov   #0xff, r14
4582:  3f40 0224      mov   #0x2402, r15
4586:  b012 b846      call  #0x46b8 <getsn>
# puts(username);
458a:  3f40 0224      mov   #0x2402, r15
458e:  b012 c846      call  #0x46c8 <puts>
# r15 为输入username的buffer end position
4592:  3f40 0124      mov   #0x2401, r15
4596:  1f53           inc   r15
4598:  cf93 0000      tst.b 0x0(r15)
459c:  fc23           jnz   $-0x6 <login+0x36>
# int r11 = len(password);
459e:  0b4f           mov   r15, r11
45a0:  3b80 0224      sub   #0x2402, r11
# strcpy(sp, (char*)(0x2402)); //sp = 0x3ff2 将username从堆拷贝到栈。
45a4:  3e40 0224      mov   #0x2402, r14
45a8:  0f41           mov   sp, r15
45aa:  b012 f446      call  #0x46f4 <strcpy>

这段汇编的最终伪代码就如下:

{
    string username = getsn(char(*)(0x2402), 0xff); // 输入username 最大长度0xff, 储存在堆空间0x2402
    puts(username);
    int r11 = len(username);
    strcpy(sp, username); // 拷贝username到栈空间(0x3ff2)
}

可以看到,最终username是存储在栈空间上,起始位置为0x3ff2.

  1. 用户名长度判断(用户名长度不能大于32)
if (r11 >= 0x21)
5ae:  7b90 2100      cmp.b  #0x21, r11
45b2:  0628           jnc   $+0xe <login+0x60>
45b4:  1f42 0024      mov   &0x2400, r15
45b8:  b012 c846      call  #0x46c8 <puts>
# return
45bc:  3040 4244      br    #0x4442 <__stop_progExec__>

伪代码如下:

if(r11 >= 33) return;
  1. 密码输入与拷贝
# int r14 = (31-r11)&(0x1ff);  // r14= 31-len(username);
45c8:  3e40 1f00      mov   #0x1f, r14
45cc:  0e8b           sub   r11, r14
# getsn(0x2402,r14); //输入password, 长度为31-len(username);
45ce:  3ef0 ff01      and   #0x1ff, r14
45d2:  3f40 0224      mov   #0x2402, r15
45d6:  b012 b846      call  #0x46b8 <getsn>
45da:  3f40 0224      mov   #0x2402, r15
45de:  b012 c846      call  #0x46c8 <puts>
# strcpy(sp + len(username), (char*)0x2402);
45e2:  3e40 0224      mov   #0x2402, r14
45e6:  0f41           mov   sp, r15
45e8:  0f5b           add   r11, r15
45ea:  b012 f446      call  #0x46f4 <strcpy>

与username部分的输入相同,也是在0x2402堆空间输入password后,复制到栈空间用户名后面地址,同时username和password的长度和要小于32

  1. 用户名与密码长度和判断
45ee:  3f40 0124      mov   #0x2401, r15
45f2:  1f53           inc   r15
45f4:  cf93 0000      tst.b 0x0(r15)
45f8:  fc23           jnz   $-0x6 <login+0x92>
45fa:  3f80 0224      sub   #0x2402, r15
45fe:  0f5b           add   r11, r15
4600:  7f90 2100      cmp.b #0x21, r15
4604:  0628           jnc   $+0xe <login+0xb2>
uint8 r15 = len(username) + len(password);
if (r15 >= 33) return;
  1. 后面就是调用test_username_and_password_valid函数,由于该函数是直接调用系统调用INT 0x7d, 而密码又处于保护内存中,所以无法通过该函数进行unlock
4458 <test_username_and_password_valid>
...
# INT 0x7d r15(username-password), r14(save the flag whether the username and password is correct)
446a:  0e12           push  r14
446c:  0f12           push  r15
446e:  3012 7d00      push  #0x7d
4472:  b012 6446      call  #0x4664 <INT>
4476:  5f44 fcff      mov.b -0x4(r4), r15
447a:  8f11           sxt   r15
447c:  3152           add   #0x8, sp
447e:  3441           pop   r4
4480:  3041           ret

所以直接略过这一部分,继续查看后续汇编代码。

  1. 判断test_username_and_password_valid的返回,验证是否unlock
4618:  0f93           tst   r15
461a:  0524           jz    $+0xc <login+0xc6>
# 得知unlock函数的地址为: 0x444c
461c:  b012 4c44      call  #0x444c <unlock_door>
4620:  3f40 3245      mov   #0x4532 "Access granted.", r15
4624:  023c           jmp   $+0x6 <login+0xca>
4626:  3f40 4245      mov   #0x4542 "That password is not correct.", r15
462a:  b012 c846      call  #0x46c8 <puts>
# sp = sp+0x22+2
462e:  3150 2200      add   #0x22, sp
4632:  3b41           pop   r11
# pc = @sp
4634:  3041           ret

题解

栈上username起始位置0x3ff2 ,username可以输入的最大长度为0x20,而栈顶到ret 的地址长度为0x24,虽然单独输入username无法覆盖ret的地址,从而控制程序执行unlock函数,但是接着username输入的为password,其输入(getsn函数)长度的计算方式为:
len(password) = (31-len(username))&(0x1ff)
如果我们输入username长度为32, 就可以使输入password长度参数为(31-32)&0x1ff = 0x1ff。从而可以覆盖ret的位置。
但是我们还要解决对于username+password长度的判断逻辑:

uint8 r15 = len(username) + len(password);
if (r15 >= 33) return;

由于r15的范围仅为0-ff,我们输入的username长度为0x20,而password长度范围可为0-0x1ff, 只要我们输入len(password) = 0x100 - 0x20,就可以使
uint8 r15 = len(username) + len(password) = 0x0;从而满足 长度和小于32的要求。
username输入32位后,password的起始地址为:0x3ff2+0x20=0x4012,如果password想要覆盖ret位置到unlock_door,也就是password的第5-6位必须输入:0x4c44(LD)(小端,取指令时会变成0x444c),且password的长度需要为0xe0.
综上,我们输入:

username = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
password = "LD"*0x70
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 以下为学python以来知识点及练习记录,用于个人知识点复习 DAY01-02 介绍、变量、格式化输出 1.pyt...
    阿杜_12a9阅读 972评论 0 3
  • MSSQL 跨库查询(臭要饭的!黑夜) 榨干MS SQL最后一滴血 SQL语句参考及记录集对象详解 关于SQL S...
    碧海生曲阅读 5,751评论 0 1
  • https://www.cnblogs.com/vame1/p/5776808.html 比方说在查询id是50的...
    小浪崇礼阅读 337评论 0 0
  • /**ios常见的几种加密方法: 普通的加密方法是讲密码进行加密后保存到用户偏好设置( [NSUserDefaul...
    彬至睢阳阅读 3,076评论 0 7
  • 姓名:于川皓 学号:16140210089 转载自:https://baike.baidu.com/item/sq...
    道无涯_cc76阅读 2,000评论 0 2