echoCTF Argum_E_Nvative (ID#10) Reverse Engineering Writeup
Category: Reverse Engineering / easy / 1,500pts
File: Argum_E_Nvative.zip (contains a statically-linked ELF x86_64 binary)
Challenge link: https://echoctf.red/challenge/10
1. Objective
Analyze the binary and answer the 4 questions the challenge asks:
- Q1: How should the program be executed?
- Q2: What is the expected env flag (ETSCTF)?
- Q3: What is the expected begging argument?
- Q4: Once the prerequisites are satisfied, what is the correct source answer that the binary prints?
2. Static Inspection
- First just run it and see what happens
└─$ ./Argum_E_Nvative.bin
Checking argv0... incorrect
Checking argc... 1 incorrect
Checking path[] exists... exists, Checking st_size==4096... correct
Checking ets_env... null
Checking home_env... incorrect
Checking argv[2]... incorrect
The ETSCTF source answer is... (drum roll please)
&wX%!*'hmrkOOPiy'')fileshows: ELF 64-bit LSB executable, static, not stripped (so it can be decompiled).- Decompiling
mainwith Ghidra lets us read the program's checking logic directly.
3. A Closer Look at main After Ghidra Decompilation
- First it reads two environment variables:
local_118 = getenv("HOME")andlocal_110 = getenv("ETSCTF"). - It checks
argv[0]:strcmp((char *)*argv, "./fdd35ef750404db0be89f31f116c2d23").- If they match → mark
argv0correct, and placeargv0[3]andargv0[2]into the output array (the ETSCTF result buffer). - Otherwise it places two random characters (rand).
- If they match → mark
- It checks
argc: only ifargc == 3does it go on to checkargv[1]; otherwiseargcis judged incorrect and filled with rand. - It checks
argv[1]:strcmp(argv[1], "-e"). If they match, it placesargv1[0](i.e.'-') into the output array; otherwise it places rand. - It checks the path
"/."(stat(local_78,&st)) — if it exists it callssetFlagFileProperties().- If it matches →
ets_env correct, and the program extracts 6 characters at specific positions from that env string (indexes: 10, 0x16(=22), 6, 0x11(=17), 0x12(=18), 9) and appends them in order to the output array. - Otherwise it appends 6 rand characters.
- If it matches →
- It checks
HOMEand whether it's running as root (geteuid()):- If
HOMEis non-empty andgeteuid()==0→home_env correct, appendHOME[0]andHOME[2]. - Otherwise append
HOME[1]andHOME[3](the program still pulls characters out of HOME to build the string).
- If
- It checks
argv[2]:strcmp(argv[2], "PleaseGiveMeTheFlag").- If they match → append a series of characters from specific indexes of
argv2(in the order: +0x12, +0x0f, +3, +10, +5, +9, +1, +8, +0, +0x12), 10 characters in all. - Otherwise append 10 rand characters.
- If they match → append a series of characters from specific indexes of
- Finally it prints
"The ETSCTF source answer is... (drum roll please) "followed by the assembledETSCTFstring (which is the source answer the challenge wants).
It checks whether the ETSCTF environment variable exists, and compares it against a whole long string:
"Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae"
So to get a deterministic (non-random) source answer, you have to make every one of those checks take the "correct" branch (i.e.argv0,argc,argv1, theETSCTFenv,HOME(with euid==0), andargv2all match their expected values).
4. Explanation of Q1–Q4
Q1 (brief)
In main the program directly uses
strcmp(argv[0], "./fdd35ef750404db0be89f31f116c2d23")
to check the program name at runtime (argv[0]), so the correct way to run it is to invoke it under the name ./fdd35ef750404db0be89f31f116c2d23.
Q2 — What is the expected env flag? (350 pts)
Answer:
Would it save you a lot of time if I just gave up and went mad now? ETSCTF_Redacted
Explanation: the program gets this env with getenv("ETSCTF") and compares it against the whole string above with strcmp; only an exact match takes the correct branch and extracts the designated characters from it.
Q3 — What is the expected begging argument? (350 pts)
Answer (exact string):
PleaseGiveMeTheFlag
Explanation: the program judges via strcmp(argv[2], "PleaseGiveMeTheFlag"), and if they match it extracts characters from several designated indexes of argv[2] to form part of the output.
Q4 — What is the correct source answer? (500 pts)
Answer:
Just run this in full~
sudo env HOME=/root ETSCTF='Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae' bash -c "exec -a './fdd35ef750404db0be89f31f116c2d23' ./Argum_E_Nvative.bin -e PleaseGiveMeTheFlag"Explanation:
- When every check reaches
correct(argv0, argc, argv1, the ETSCTF env, home_env, and argv2 all matching the program's internal expectations), the program extracts specific bytes from each of these sources in order and appends them into the final string; printing that string gives the source answer Q4 asks for.
└─$ sudo env HOME=/root ETSCTF='Would it save you a lot of time if I just gave up and went mad now? ETSCTF_02ea5de333a4f296b8aa8bf0925a90ae' bash -c "exec -a './fdd35ef750404db0be89f31f116c2d23' ./Argum_E_Nvative.bin -e PleaseGiveMeTheFlag"
Checking argv0... correct
Checking argc... 3 correct
Checking argv[1]... correct
Checking path[] exists... exists, Checking st_size==4096... correct
Checking ets_env... not null, correct
Checking home_env... correct
Checking argv[2]... correct
The ETSCTF source answer is... (drum roll please)
df-%!*'ati as/ogFaMeelvPgLessons Learned
On section 3:
Here I used Ghidra to pull out the entire decompiled logic of "main"! The trick is that in Ghidra you can first search all the strings, then hunt for certain keywords — for example, I searched for argv, and that led me straight to main.

Member discussion