# read_req() ~~~~~{.c} 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)
- Can't overwrite the return addr (of read_req)?
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)
- OpenSSL: popular SSL/TLS library
- Heartbeat: keep connections alive even if no data to be transmitted
- Send <-> response (identical copy of the payload)
~~~~~{.c}
struct Msg {
u8 type; /* 1 bytes */
u16 length; /* 2 bytes */
char* payload; /* len(payload) = length */
char* padding[]; /* minimum: 16 */
};
~~~~~
# Code (@ssl/d1_both.c)
~~~~~{.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)
~~~~~{.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);
~~~~~
# {.cover .w}
![](xkcd.png)
# Consequences
- Dump upto 64KB of memory
- It might contain sensitive data
(e.g., secrete key, passwd &c)
- What should we do?
# Fixes (@ssl/d1_both.c)
~~~~~{.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
- A naive mistake can destroy the entire trust chains
- Don't write own parser?
- Don't use C?
# CS101: quiz