read_req()

  void read_req(void) {
    char buf[128];
    int i;
    gets(buf);
    i = atoi(buf);
  }

Exploit (if stack grows down)


      0x00
        ^         ....
        |  +------------------+ <- esp
           |   return addr.   |
           +------------------+
           |      &buf        |
           +------------------+
           |        i         |
           +------------------+            +----------+<--+
           |     buf[0:3]     |            | shell    |   |
           |      ...         |            | code     |   |
           +------------------+ <- ebp     |          |   |
           |    saved ebp     |            |          |   |
           +------------------+            |          |   |
           |   return addr    |            |//////////|---+
           +------------------+            +----------+
  

Exploit (if stack grows up)


        0x00
           +------------------+
           |   return addr.   |
           +------------------+
           |    saved ebp     |
           +------------------+            +----------+
           |     buf[0:3]     |            | shell    |
           |      ...         |            | code     |
           +------------------+            |          |
           |        i         |            |          |
         | +------------------+            +----------+
         v        ...
  

Exploit (if stack grows up)


        0x00
           +------------------+
           |   return addr.   |
           +------------------+
           |    saved ebp     |
           +------------------+ <---+      +----------+<--+
           |     buf[0:3]     |     |      | shell    |   |
           |      ...         |     |      | code     |   |
           +------------------+     |      |          |   |
           |        i         |     |      |          |   |
           +------------------+     |      |          |   |
           |      &buf        | ----+      |          |   |
           +------------------+            |          |   |
           |   return addr.   |            |//////////|---+
           +------------------+            +----------+
           |    saved ebp     |
         | +------------------+
         v        ...
  

Heartbleed (CVE-2014-0160)

  struct Msg {
    u8    type;      /* 1 bytes */
    u16   length;    /* 2 bytes */
    char* payload;   /* len(payload) = length */
    char* padding[]; /* minimum: 16 */
  };

Code (@ssl/d1_both.c)

  // Msg = [type][len][payload][padding]
  type = *p++;     // p = Msg
  n2s(p, length);  // length = p.length
  payload = p;     // payload = p.payload
  
  if (type == TLS1_HB_REQUEST) {
    unsigned char *buf, *bp;
    
    buf = OPENSSL_malloc(1 + 2 + length + padding);
    bp = buf;

Code (@ssl/d1_both.c)

    // bp = Msg (type/length)
    *bp++ = TLS1_HB_RESPONSE;
    s2n(length, bp);
  
    // copy payload to the buffer
    memcpy(bp, payload, length);
    ssl3_write_bytes(s, TLS1_RT_HEARTBEAT,
                      buf, 1 + 2 + length + padding);

Consequences

Fixes (@ssl/d1_both.c)

  /* discard zero-size heartbeat */
  if (1 + 2 + 16 > s->s3->rrec.length)
      return 0;
      
  type = *p++;
  n2s(p, payload);
  
  /* discard if it lies */
  if (1 + 2 + payload + 16 > s->s3->rrec.length)
      return 0;

Lessons

CS101: quiz
(by John Regehr)

Q1. What does the expression 1 > 0 evaluate to?

  1. 0
  2. 1
  3. undefined

Q2. 1U > -1?

  1. 0
  2. 1
  3. undefined

Q3. (unsigned short)1 > -1?

  1. 0
  2. 1
  3. undefined

Q4. -1L > 1U? on x86-64? on x86?

  1. 0 on both platforms
  2. 1 on both platforms
  3. 0 on x86-64, 1 on x86
  4. 1 on x86-64, 0 on x86

Q5. SCHAR_MAX == CHAR_MAX?

  1. 0
  2. 1
  3. undefined

Q6. UINT_MAX + 1?

  1. 0
  2. 1
  3. INT_MAX
  4. UINT_MAX
  5. undefined

Q7. INT_MAX + 1?

  1. 0
  2. 1
  3. INT_MAX
  4. UINT_MAX
  5. INT_MIN
  6. undefined

Q8. -INT_MIN?

  1. 0
  2. 1
  3. INT_MAX
  4. UINT_MAX
  5. INT_MIN
  6. undefined

Q9. Assume x has type int. Is the expression x<<0...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q10. Assume x has type int. Is the expression x<<1...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q11. Assume x has type int. Is the expression x<<31...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q12. Assume x has type int. Is the expression x<<32...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q13. Assume x has type short. Is the expression x<<29...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q14. Assume x has type unsigned. Is the expression x<<31...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q15. Assume x has type unsigned short. Is the expression x<<31...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q16. Assume x has type int. Is the expression x + 1...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q17. Assume x has type int. Is the expression x - 1 + 1...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q18. Assume x has type int. Is the expression (short)x + 1...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

Q19. Assume x has type int. Is the expression (short)(x + 1)...

  1. defined for all values of x
  2. defined for some values of x
  3. defined for no values of x

kint

Q1

Q2.