\0 if prefixed with backslashstrlen used to allocate buffer0x000056291a25d502 in process_hooks_getenv (name=name@...ry=0x7f4a6d7dc046 "SYSTEMD_BYPASS_USERDB", value=value@...ry=0x7ffc595cc240) at ../../src/hooks.c:108
=> 0x56291a25d502 <process_hooks_getenv+82>: callq *0x8(%rbx)
108 rc = hook->u.getenv_fn(name, &val, hook->closure);
*** interesting standard library function: ***
0000000000008a00 <execv@plt>:
8a00: endbr64
8a04: bnd jmpq *0x55565(%rip) # 5df70 <execv@GLIBC_2.2.5>
8a0b: nopl 0x0(%rax,%rax,1)
...
*** usual value of function pointer: ***
000000000000ea00 <sudoers_hook_getenv>:
ea00: endbr64
ea04: xor %eax,%eax
ea06: cmpb $0x0,0x51d36(%rip) # 60743 <sudoers_policy@@Base+0x2003>
ea0d: jne eaf8 <freeaddrinfo@plt+0x60a8>
ea13: cmpq $0x0,0x51d45(%rip) # 60760 <sudoers_policy@@Base+0x2020>
observations (that hold true even with ASLR):
execv@plt) - addr(sudoers_hook_getenv) = -0x6000a00 (page alignment)suppose hook_getenv pointer is 0xabcdef8a00
00 8a ef cd ab 00 00 00then execv@plt pointer is 0xabcdef3a00
00 3a ef cd ab 00 00 00solution: guess hook_getenv pointer at 0x (unknown) 8a00
overwrite last two bytes with 00 3a
if right: will execute your program
if wrong: will crash
what if crashes? try again!
make SYSTEMD_BYPASS_USERDB program in current directory
run sudo, triggering buffer overflow to change sudoers_hook_getenv("SYSTEMD_BYPASS_USERDB", ...)
into execv("SYSTEMD_BYPASS_USERDB", ...)
brk()
mmap()
int free(void *object) {
...
block_after = object + object_size;
if (block_after->free) {
/* unlink from list,
prepare to merge with previous block */
new_block->size += block_after->size;
block_after->prev->next = block_after->next;
block_after->next->prev = block_after->prev;
}
...
}
void operator delete(void *p) {
...
block_after->prev->next = block_after->next;
...
}
...
class MyBuffer : public GenericMyBuffer {
public:
virtual void store(const char *p) override {
strcpy(buffer, p);
}
private:
char buffer[64];
};
...
GenericMyBuffer *a = new MyBuffer;
...
a->store(attacker_controlled);
...
delete a;
...| size + free (8B) |
| vtable pointer (8B) |
| buffer (64B) |
| size + free (8B) |
| next pointer (8B) |
| prev pointer (8B) |
a is free; if a at address 0x10000, and attacker wants to overwrite value at address 0x21210, where should attacker put encoding of 0x21210 in attacker_controlled?| A. 64 bytes in | B. 72 bytes in | C. 80 bytes in |
| D. 88 bytes in | E. something else |
a at address 0x10000, and attacker wants to overwrite value at address 0x21210, how should attacker encode if placing 80 bytes in?
| A. 0x21210 (as 64-bit int) | B. 0x21210-8 | C. 0x21210+8 |
| D. 0x21210+16 | E. 0x21210-16 | F. something else |
a is free; value at address 0x21210 with 0x31310, and they put 0x21210-8 80 bytes in, where should they put 0x31310?
| A. 64 bytes in | B. 72 bytes in | C. 80 bytes in |
| D. 88 bytes in | E. something else |
b at address 0x10000, and attacker wants to overwrite value at address 0x21210 with 0x31310, how should they encode 0x31310?
| A. 0x31310 (as 64-bit int) | B. 0x31310-8 | C. 0x31310+8 |
| D. 0x31310+16 | E. 0x31310-16 | F. something else |
exercise 2:
Suppose space after a is not free. Can we still exploit?
malloc returns something still on free list
because double-free made loop in the linked list
attacker can overwrite next pointer
controls where future malloc() goes
// free/delete 1:
double_freed->next = first_free;
first_free = chunk;
// free/delete 2:
double_freed->next = first_free;
first_free = chunk
// malloc/new 1:
result1 = first_free;
first_free = first_free->next;
// + overwrite:
strcpy(result1, ...);
// malloc/new 2:
first_free = first_free->next;
// malloc/new 3:
result3 = first_free;
strcpy(result3, ...);
size data)free(...) {
freed->next = first_free
first_free = freed;
}
malloc(...) {
if (can use first free) {
void *to_return = first_free;
first_free = first_free->next;
return to_return;
}
}
vulnerable() {
char *p = malloc(100);
free(p);
free(p);
char *q = malloc(100);
char *r = malloc(100);
strlcpy(q, attacker_input1, 100);
char *s = malloc(100);
strlcpy(r, attacker_input2, 100);
strlcpy(s, attacker_input3, 100);
}goal: memory[0x123456] \(\leftarrow\) 0x789abc
what should input1/input2/input3 be?