【pwnable.kr】Toddler‘s Bottle-[random]


Target & Download


image-20211207123744058

Daddy, teach me how to use random value in programming!

ssh random@pwnable.kr -p2222 (pw:guest)

scp 下载文件

scp -P 2222 -p random@pwnable.kr:/home/random/* ./


Analysis & IDA


random.c

#include <stdio.h>

int main(){
        unsigned int random;
        random = rand();        // random value!

        unsigned int key=0;
        scanf("%d", &key);

        if( (key ^ random) == 0xdeadbeef ){
                printf("Good!\n");
                system("/bin/cat flag");
                return 0;
        }

        printf("Wrong, maybe you should try 2^32 cases.\n");
        return 0;
}

满足 (key ^ random) == 0xdeadbeef 即可

在 rand 被调用之前,srand 函数要先被调用,并且 srand 在整个程序中仅被调用一次。

这里并没有调用srand 这样其实每次运行rand 结果是不变的。

每次运行都会用同一个种子生成随机序列,那么每次程序运行得到的数就是一样的。tips

IDA pseudocode

.text:00000000004005F4 ; __unwind {
.text:00000000004005F4                 push    rbp
.text:00000000004005F5                 mov     rbp, rsp
.text:00000000004005F8                 sub     rsp, 10h
.text:00000000004005FC                 mov     eax, 0
.text:0000000000400601                 call    _rand
.text:0000000000400606                 mov     [rbp+var_4], eax
.text:0000000000400609                 mov     [rbp+var_8], 0
.text:0000000000400610                 mov     eax, offset unk_400760
.text:0000000000400615                 lea     rdx, [rbp+var_8]
.text:0000000000400619                 mov     rsi, rdx
.text:000000000040061C                 mov     rdi, rax
.text:000000000040061F                 mov     eax, 0
.text:0000000000400624                 call    ___isoc99_scanf
.text:0000000000400629                 mov     eax, [rbp+var_8]
.text:000000000040062C                 xor     eax, [rbp+var_4]
.text:000000000040062F                 cmp     eax, 0DEADBEEFh
.text:0000000000400634                 jnz     short loc_400656
.text:0000000000400636                 mov     edi, offset s   ; "Good!"
.text:000000000040063B                 call    _puts
.text:0000000000400640                 mov     edi, offset command ; "/bin/cat flag"
.text:0000000000400645                 mov     eax, 0
.text:000000000040064A                 call    _system
.text:000000000040064F                 mov     eax, 0
.text:0000000000400654                 jmp     short locret_400665
.text:0000000000400656 ; ---------------------------------------------------------------------------
.text:0000000000400656

Debug & writeup


ELF 文件,使用gdb debug

.text:0000000000400601                 call    _rand
.text:0000000000400606                 mov     [rbp+var_4], eax
.text:0000000000400609                 mov     [rbp+var_8], 0

执行到0x400609的时候已经获取到_rand 生成的伪随机数了。

在此处打断点,查看rbp+4h的数据,即可获得

使用pwndbg

hispark@ubuntu:~/code/pwndbg$ gdb gdb/random 
Reading symbols from gdb/random...(no debugging symbols found)...done.
pwndbg> b *0x400609
Breakpoint 1 at 0x400609
pwndbg> rub
Undefined command: "rub".  Try "help".
pwndbg> run
Starting program: /home/hispark/code/pwndbg/gdb/random 

Breakpoint 1, 0x0000000000400609 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
 RAX  0x6b8b4567
 RBX  0x0
 RCX  0x7ffff7dcd1c8 (randtbl+8) ◂— 0x6774a4cd16a5bce3
 RDX  0x0
 RDI  0x7ffff7dcd740 (unsafe_state) —▸ 0x7ffff7dcd1d4 (randtbl+20) ◂— 0x61048c054e508aaa
 RSI  0x7fffffffdd14 ◂— 0x94e50d006b8b4567
 R8   0x7ffff7dcd1d4 (randtbl+20) ◂— 0x61048c054e508aaa
 R9   0x7ffff7dcd240 (pa_next_type) ◂— 0x8
 R10  0x3
 R11  0x7ffff7a264c0 (rand) ◂— sub    rsp, 8
 R12  0x400510 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffde30 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdd50 —▸ 0x400670 (__libc_csu_init) ◂— mov    qword ptr [rsp - 0x28], rbp
 RSP  0x7fffffffdd40 —▸ 0x7fffffffde30 ◂— 0x1
 RIP  0x400609 (main+21) ◂— mov    dword ptr [rbp - 8], 0
───────────────────────────────────[ DISASM ]───────────────────────────────────
 ► 0x400609 <main+21>    mov    dword ptr [rbp - 8], 0
   0x400610 <main+28>    mov    eax, 0x400760
   0x400615 <main+33>    lea    rdx, [rbp - 8]
   0x400619 <main+37>    mov    rsi, rdx
   0x40061c <main+40>    mov    rdi, rax
   0x40061f <main+43>    mov    eax, 0
   0x400624 <main+48>    call   __isoc99_scanf@plt                      <__isoc99_scanf@plt>
 
   0x400629 <main+53>    mov    eax, dword ptr [rbp - 8]
   0x40062c <main+56>    xor    eax, dword ptr [rbp - 4]
   0x40062f <main+59>    cmp    eax, 0xdeadbeef
   0x400634 <main+64>    jne    main+98                      <main+98>
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp 0x7fffffffdd40 —▸ 0x7fffffffde30 ◂— 0x1
01:0008│     0x7fffffffdd48 ◂— 0x6b8b456700000000
02:0010│ rbp 0x7fffffffdd50 —▸ 0x400670 (__libc_csu_init) ◂— mov    qword ptr [rsp - 0x28], rbp
03:0018│     0x7fffffffdd58 —▸ 0x7ffff7a03bf7 (__libc_start_main+231) ◂— mov    edi, eax
04:0020│     0x7fffffffdd60 ◂— 0x1
05:0028│     0x7fffffffdd68 —▸ 0x7fffffffde38 —▸ 0x7fffffffe1d7 ◂— '/home/hispark/code/pwndbg/gdb/random'
06:0030│     0x7fffffffdd70 ◂— 0x100008000
07:0038│     0x7fffffffdd78 —▸ 0x4005f4 (main) ◂— push   rbp
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
 ► f 0         0x400609 main+21
   f 1   0x7ffff7a03bf7 __libc_start_main+231
   f 2         0x400539 _start+41
────────────────────────────────────────────────────────────────────────────────
pwndbg> 

image-20211207193540278

rbp+4h 即 01:0008 0x6b8b456700000000 则random为 0x6b8b4567

hispark@ubuntu:~/code/pwndbg$ python
Python 2.7.17 (default, Feb 27 2021, 15:10:58) 
[GCC 7.5.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> random = 0x6b8b4567
>>> res = 0xdeadbeef
>>> key = res ^ ramdom
>>> key = res ^ random
>>> print(key)
3039230856
>>> 

利用异或的运算即可获得最终值3039230856

random@pwnable:~$ ./random
3039230856
Good!
Mommy, I thought libc random is unpredictable...
random@pwnable:~$

TIPS


int rand(void);
int rand_r(unsigned int *seedp);
void srand(unsigned int seed);
  • 在rand函数的内部,是通过一个公式计算出一个值作为随机值,下次再调用rand的时候,再把这个随机值作为参数传给这个公式计算出一个新的随机值,周而复始。
  • 在C库中,是通过一个静态全局变量来作为“种子”,而这个“种子”的值是通过srand函数改变的,如果不写srand函数,这个“种子”值默认赋值为1。
  • 程序只要重新开始运行,“种子”值就会被默认赋值为1,那么通过公式算出来的序列肯定就一直相同了。
  • 目前流传较广的意见是rand_r函数是线程安全的。

参考:

https://blog.csdn.net/lvyibin890/article/details/80141412

https://blog.csdn.net/w_y_x_y/article/details/80199694

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值