欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【pwnable.kr】random

程序员文章站 2022-05-15 14:14:20
...

【pwnable.kr】random

download

scp -P 2222 -p  aaa@qq.com:/home/random/* ./
程序输入用scanf %d 读取一个signed int和rand()异或,如果结果为0xdeadbeef进入system流程。
由于rand()调用前没有调用srand(),因此产生的结果可以认为是不变的。 
关于异或:A ^ B = C -> A ^ C = B -> B ^ C = A ,任意两个变量异或的值等于第三个值。
gdb本地调试,断点设置在rand()后,b *0x400606,可知rand的结果为0x6b8b4567。

>>> 0x6b8b4567^0xdeadbeef
3039230856
IDA pseudocode
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+8h] [rbp-8h]
  int v5; // [rsp+Ch] [rbp-4h]

  v5 = rand();
  v4 = 0;
  __isoc99_scanf(&unk_400760, &v4);
  if ( (v5 ^ v4) == 0xDEADBEEF )
  {
    puts("Good!");
    system("/bin/cat flag");
  }
  else
  {
    puts("Wrong, maybe you should try 2^32 cases.");
  }
  return 0;
}

TIPS
    #include <stdlib.h>
    int rand(void);
    int rand_r(unsigned int *seedp);
    void srand(unsigned int seed);
rand() returns a pseudo-random integer. Without srand(),the return value is 1804289383. 
srand() can change the seed which will effect rand(). # default srand(1) 
rand_r()’s seedp argument is used to store state between calls.
See more at: http://man7.org/linux/man-pages/man3/rand.3.html and glibc also. 

#include <stdio.h>
#include <stdlib.h>
void myrand(){
    int a;
    a = rand();
    printf("rand() value # %d\n", a);
}
void mysrand(){
    int a;
    srand(1);
    a = rand();
    printf("srand(1)  rand() value %d\n", a);
}
void main(){
    myrand();
    mysrand();

}
/*
Output:
    rand() value # 1804289383
    srand(1)  rand() value 1804289383
*/

EXPLOIT

aaa@qq.com:~$ ./random
3039230856
Good!
Mommy, I thought libc random is unpredictable...
glibc optional

Here is the source code of rand srand and rand_r() for reference only.Yes, I haven’t read it…

// stdlib/rand.c
/* Return a random integer between 0 and RAND_MAX.  */
int
rand (void)
{
  return (int) __random ();
}

// stdlib/random.c
long int
__random (void)
{
  int32_t retval;

  __libc_lock_lock (lock);

  (void) __random_r (&unsafe_state, &retval);

  __libc_lock_unlock (lock);

  return retval;
}

// stdlib/random_r.c
int
__random_r (struct random_data *buf, int32_t *result)
{
  int32_t *state;

  if (buf == NULL || result == NULL)
    goto fail;

  state = buf->state;

  if (buf->rand_type == TYPE_0)
    {
      int32_t val = state[0];
      val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
      state[0] = val;
      *result = val;
    }
  else
    {
      int32_t *fptr = buf->fptr;
      int32_t *rptr = buf->rptr;
      int32_t *end_ptr = buf->end_ptr;
      int32_t val;

      val = *fptr += *rptr;
      /* Chucking least random bit.  */
      *result = (val >> 1) & 0x7fffffff;
      ++fptr;
      if (fptr >= end_ptr)
    {
      fptr = state;
      ++rptr;
    }
      else
    {
      ++rptr;
      if (rptr >= end_ptr)
        rptr = state;
    }
      buf->fptr = fptr;
      buf->rptr = rptr;
    }
  return 0;

 fail:
  __set_errno (EINVAL);
  return -1;
}
// stdlib/random.c
void
__srandom (unsigned int x)
{
  __libc_lock_lock (lock);
  (void) __srandom_r (x, &unsafe_state);
  __libc_lock_unlock (lock);
}
// stdlib/random_r.c
/* Initialize the random number generator based on the given seed.  If the
   type is the trivial no-state-information type, just remember the seed.
   Otherwise, initializes state[] based on the given "seed" via a linear
   congruential generator.  Then, the pointers are set to known locations
   that are exactly rand_sep places apart.  Lastly, it cycles the state
   information a given number of times to get rid of any initial dependencies
   introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
   for default usage relies on values produced by this routine.  */
int
__srandom_r (unsigned int seed, struct random_data *buf)
{
  int type;
  int32_t *state;
  long int i;
  int32_t word;
  int32_t *dst;
  int kc;

  if (buf == NULL)
    goto fail;
  type = buf->rand_type;
  if ((unsigned int) type >= MAX_TYPES)
    goto fail;

  state = buf->state;
  /* We must make sure the seed is not 0.  Take arbitrarily 1 in this case.  */
  if (seed == 0)
    seed = 1;
  state[0] = seed;
  if (type == TYPE_0)
    goto done;

  dst = state;
  word = seed;
  kc = buf->rand_deg;
  for (i = 1; i < kc; ++i)
    {
      /* This does:
       state[i] = (16807 * state[i - 1]) % 2147483647;
     but avoids overflowing 31 bits.  */
      long int hi = word / 127773;
      long int lo = word % 127773;
      word = 16807 * lo - 2836 * hi;
      if (word < 0)
    word += 2147483647;
      *++dst = word;
    }

  buf->fptr = &state[buf->rand_sep];
  buf->rptr = &state[0];
  kc *= 10;
  while (--kc >= 0)
    {
      int32_t discard;
      (void) __random_r (buf, &discard);
    }

 done:
  return 0;

 fail:
  return -1;
}
// stdlib/random_r.c

/* This algorithm is mentioned in the ISO C standard, here extended
   for 32 bits.  */
int
rand_r (unsigned int *seed)
{
  unsigned int next = *seed;
  int result;

  next *= 1103515245;
  next += 12345;
  result = (unsigned int) (next / 65536) % 2048;

  next *= 1103515245;
  next += 12345;
  result <<= 10;
  result ^= (unsigned int) (next / 65536) % 1024;

  next *= 1103515245;
  next += 12345;
  result <<= 10;
  result ^= (unsigned int) (next / 65536) % 1024;

  *seed = next;

  return result;
}