4 min read

echoCTF Argum_E_Nvative (ID#10) Reverse Engineering Writeup

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'')
  • file shows: ELF 64-bit LSB executable, static, not stripped (so it can be decompiled).
  • Decompiling main with Ghidra lets us read the program's checking logic directly.

3. A Closer Look at main After Ghidra Decompilation

  1. First it reads two environment variables: local_118 = getenv("HOME") and local_110 = getenv("ETSCTF").
  2. It checks argv[0]: strcmp((char *)*argv, "./fdd35ef750404db0be89f31f116c2d23").
    • If they match → mark argv0 correct, and place argv0[3] and argv0[2] into the output array (the ETSCTF result buffer).
    • Otherwise it places two random characters (rand).
  3. It checks argc: only if argc == 3 does it go on to check argv[1]; otherwise argc is judged incorrect and filled with rand.
  4. It checks argv[1]: strcmp(argv[1], "-e"). If they match, it places argv1[0] (i.e. '-') into the output array; otherwise it places rand.
  5. It checks the path "/." (stat(local_78,&st)) — if it exists it calls setFlagFileProperties().
    • 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.
  6. It checks HOME and whether it's running as root (geteuid()):
    • If HOME is non-empty and geteuid()==0home_env correct, append HOME[0] and HOME[2].
    • Otherwise append HOME[1] and HOME[3] (the program still pulls characters out of HOME to build the string).
  7. 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.
  8. Finally it prints "The ETSCTF source answer is... (drum roll please) " followed by the assembled ETSCTF string (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, the ETSCTF env, HOME (with euid==0), and argv2 all 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/ogFaMeelvPg

Lessons 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.

Ghidra decompilation view of the Argum_E_Nvative binary's main function