Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use After Free #10

Closed
AiDaiP opened this issue Jan 2, 2022 · 1 comment
Closed

Use After Free #10

AiDaiP opened this issue Jan 2, 2022 · 1 comment

Comments

@AiDaiP
Copy link

AiDaiP commented Jan 2, 2022

Use After Free

Description

I am learning model checking. But I run a fuzzer for fun today.

My fuzzer has found a Use After Free in modex.

The chunk 0x5555555b96b0 was freed.Then the tcache key was covered and the chunk was freed again.

version

acfa291

modex -V
MODEX Version 2.11 - 3 November 2017

System information
Ubuntu 20.04 focal, AMD EPYC 7742 64-Core @ 16x 2.25GHz

poc

base64 poc
dHlwZWRlZiBzdHJ1Y3QgRW50cnkgRW50cnk7CgpzdHJ1Y3QgRW50cnkgewp9CglFbnRyeSBoZWFk
OwoJZm9yICh2YWwgPSAwOyB2YWwgPCAycmV0dXJuOyB2YWwrKyl9Cgp2b2lkICoKcnRsX2dldCh2
b2lkICphcmcpCnsJNG50cnkgKnE7CgkJbmV4dCA9IHEtPm5leHQ7CmlmIDsxPT0wKQoJCWUgPSBu
ZXh0LT5uZXh0O3ggPSBjewoJCW5leHQgPSBxLT5uZXh0OwoJCWlmICgoeCA9PSAwKTsKCglpZiAo
cS0+bmV4dGVtcCBuaWwgJiYgZSA9PSAwKQoJewl4ID0gY2FzKCZxLT50YWlsLCBuZXh0LCBxKTsK
CQlpZih4ID09IDApCgkJewljYXMoJm5leHQtPm5leHQsIG5pbCwgbmV4dC0+dMptcCk7CgkJCS0+
bmV4YXNzZXJ0KG5leHQ8PnZhbHVlID2AAAAAIHZhbDEgKyAxIHx8IG5leHQtPnZhbHVlID09IHZh
bDIgKyAxcnkgaGVhZDsKRW50cnkgKm5pbCA9O3ByZXYtPnRlbXAgPSBuZXc7CgkJZGVjdmFsMSAr
IDEpCgkJdmFsMSsrOwp9CgppbnQKbWFpbih2b2lkKQp9CglyZXR1cm4gMDsKfQo=

command

./modex ./poc.c

Result

modex poc.c
MODEX Version 2.11 - 3 November 2017
poc.c:4: Error (syntax error, unexpected RBRACE) before '}'
}
^
poc.c:6: Error (syntax error, unexpected FOR) before 'for'
 for (val = 0; val < 2return; val++)}
 ^
poc.c:10: Error (syntax error, unexpected IDENT, expecting SEMICOLON) before 'Identifier'
{ 4ntry *q;
   ^
poc.c:12: Error (syntax error, unexpected SEMICOLON, expecting LPAREN) before ';'
if ;1==0)
   ^
poc.c:12: Error (syntax error, unexpected RPAREN, expecting SEMICOLON) before ')'
if ;1==0)
        ^
poc.c:13: Error (syntax error, unexpected LBRACE, expecting SEMICOLON) before '{'
  e = next->next;x = c{
                      ^
poc.c:15: Error (syntax error, unexpected SEMICOLON, expecting RPAREN) before ';'
  if ((x == 0);
              ^
poc.c:17: Error (syntax error, unexpected IDENT, expecting RPAREN) before 'Identifier'
 if (q->nextemp nil && e == 0)
                ^
poc.c:20: Error (syntax error, unexpected RPAREN, expecting SEMICOLON) before ')'
  decval1 + 1)
             ^
poc.c:26: Error (syntax error, unexpected RBRACE, expecting LBRACE) before '}'
}
^
too many errors (10 detected)
10 errors
free(): double free detected in tcache 2
[1]    3645907 abort      modex poc.c

gdb

watch *0x5555555b96b0

c 34

n

pwndbg>
0x00007ffff7cf603e      863     in libioP.h
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────[ REGISTERS ]──────────────────────────────────────
 RAX  0xffffff00
 RBX  0x7ffff7e5e4a0 (_IO_file_jumps) ◂— 0x0
 RCX  0xffffffffffffffb0
 RDX  0x1c500
*RDI  0x5555555b96b0 —▸ 0x5555555ba020 ◂— 0x0
 RSI  0x0
 R8   0x8000
 R9   0xa
 R10  0x5555555988f6 ◂— ' errors\n'
 R11  0x246
 R12  0xffffffff
 R13  0x7fffffffe180 ◂— 0x2
 R14  0x0
 R15  0x0
 RBP  0x5555555b96b0 —▸ 0x5555555ba020 ◂— 0x0
 RSP  0x7fffffffdc90 —▸ 0x55555558c130 (__libc_csu_init) ◂— endbr64
*RIP  0x7ffff7cf603e (fclose+238) ◂— call   0x7ffff7c96330
───────────────────────────────────────[ DISASM ]────────────────────────────────────────
   0x7ffff7cf602e <fclose+222>    or     dl, al
   0x7ffff7cf6030 <fclose+224>    jne    fclose+243                <fclose+243>

   0x7ffff7cf6032 <fclose+226>    cmp    rbp, qword ptr [rip + 0x165e57]
   0x7ffff7cf6039 <fclose+233>    je     fclose+243                <fclose+243>

   0x7ffff7cf603b <fclose+235>    mov    rdi, rbp
 ► 0x7ffff7cf603e <fclose+238>    call   free@plt                <free@plt>
        ptr: 0x5555555b96b0 —▸ 0x5555555ba020 ◂— 0x0

   0x7ffff7cf6043 <fclose+243>    mov    eax, r12d
   0x7ffff7cf6046 <fclose+246>    pop    rbx
   0x7ffff7cf6047 <fclose+247>    pop    rbp
   0x7ffff7cf6048 <fclose+248>    pop    r12
   0x7ffff7cf604a <fclose+250>    ret
────────────────────────────────────────[ STACK ]────────────────────────────────────────
00:0000│ rsp 0x7fffffffdc90 —▸ 0x55555558c130 (__libc_csu_init) ◂— endbr64
01:00080x7fffffffdc98 —▸ 0x7fffffffdcc0 —▸ 0x7fffffffdf40 —▸ 0x7fffffffe090 ◂— 0x0
02:00100x7fffffffdca0 —▸ 0x5555555585c0 (_start) ◂— endbr64
03:00180x7fffffffdca8 —▸ 0x55555555b17e (Fclose+69) ◂— nop
04:00200x7fffffffdcb0 —▸ 0x555555573208 (top_of_stack+28) ◂— test   eax, eax
05:00280x7fffffffdcb8 —▸ 0x5555555b96b0 —▸ 0x5555555ba020 ◂— 0x0
06:00300x7fffffffdcc0 —▸ 0x7fffffffdf40 —▸ 0x7fffffffe090 ◂— 0x0
07:00380x7fffffffdcc8 —▸ 0x55555555f440 (process_input+883) ◂— mov    qword ptr [rbp - 0x260], 0
──────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────
 ► f 0   0x7ffff7cf603e fclose+238
   f 1   0x7ffff7cf603e fclose+238
   f 2   0x55555555b17e Fclose+69
   f 3   0x55555555f440 process_input+883
   f 4   0x55555555f780 main+624
   f 5   0x7ffff7c980b3 __libc_start_main+243
─────────────────────────────────────────────────────────────────────────────────────────
pwndbg> bin
tcachebins
0x1e0 [  2]: 0x5555555b96b0 —▸ 0x5555555ba020 ◂— 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
0xe00: 0x5555555b98f0 —▸ 0x7ffff7e5d1f0 (main_arena+1648) ◂— 0x5555555b98f0
pwndbg> x/10gx 0x5555555b96b0
0x5555555b96b0: 0x00005555555ba020      0x00005555555bba90
0x5555555b96c0: 0x00005555555bba90      0x00005555555bba90
0x5555555b96d0: 0x00005555555bba90      0x00005555555bba90
0x5555555b96e0: 0x00005555555bba90      0x0000000000000000
0x5555555b96f0: 0x0000000000000000      0x0000000000000000
pwndbg> bt
#0  0x00007ffff7cf603e in _IO_deallocate_file (fp=0x5555555b96b0) at libioP.h:863
#1  _IO_new_fclose (fp=0x5555555b96b0) at iofclose.c:74
#2  0x000055555555b17e in Fclose (fd=0x5555555b96b0) at modex.c:105
#3  0x000055555555f440 in process_input (f=0x7ffff7b6d0a0 "./poc.c", phase2=0) at modex.c:1243
#4  0x000055555555f780 in main (argc=2, argv=0x7fffffffe188) at modex.c:1306
#5  0x00007ffff7c980b3 in __libc_start_main (main=0x55555555f510 <main>, argc=2, argv=0x7fffffffe188, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe178) at ../csu/libc-start.c:308
#6  0x00005555555585ee in _start ()
@nimble-code
Copy link
Owner

Very cool find!
This one is hard to diagnose though. In looking at the code I do see that line 1225, and hence line 1243 with Fclose(fp), can be reached even when fp is not set on line 1207, e.g. when "must_preprocess" is non-zero. And, since fp is not initialized in the declaration, the pointer could have an arbitrary value from a previous call, that could then lead to the double fclose.
It's a bizarre scenario, but possible. I fixed it by initializing fp to NULL in the declaration (which would have been required in any case). I wonder if the fuzzer can still find a path?
Excellent report -- thank you for all your efforts!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants