{"id":13057,"date":"2016-06-25T13:22:34","date_gmt":"2016-06-25T11:22:34","guid":{"rendered":"http:\/\/www.codilime.com\/?p=13057"},"modified":"2016-12-01T23:19:22","modified_gmt":"2016-12-01T22:19:22","slug":"whitehat11-re1","status":"publish","type":"post","link":"https:\/\/codisec.com\/whitehat11-re1\/","title":{"rendered":"Whitehat11 RE1"},"content":{"rendered":"

Link: https:\/\/wargame.whitehat.vn\/Challenges\/DetailContest\/141<\/a>
\nPoints: 100
\nCategory: RE<\/p>\n

Description<\/h2>\n

http:\/\/material.wargame.whitehat.vn\/contests\/11\/re1_d3309936b177b41dada3796c4c3acadf.zip<\/a><\/p><\/blockquote>\n

tl;dr<\/h2>\n

see below<\/a><\/p>\n

Solving the task<\/h2>\n

When executed the program asks for input. It seems that regardless of what is being provided the answer is always “wrong<\/em>“.<\/p>\n

Simplified<\/strong> reversed C code for the program’s main function looks like the following:<\/p>\n

int __cdecl __noreturn main(int, const char**, const char**)\r\n{\r\n  const bool bCheckPtrace = detectDebugging();\r\n\r\n  if ( pipe(pipe_1) == -1 )\r\n    exit(1);\r\n  if ( pipe(pipe_2) == -1 )\r\n    exit(1);\r\n\r\n  const __pid_t pid = fork();\r\n  if ( pid != -1 ) {\r\n\r\n    if ( pid )\r\n    {\r\n      ssize_t numReada;\r\n      char bufRead[200];\r\n      char bufWrite[200];\r\n\r\n      close(pipe_1[0]);\r\n      close(pipe_2[1]);\r\n\r\n      while ( 1 )\r\n      {\r\n        puts(\"Input key : \");\r\n        memset(bufWrite, 0, 200);\r\n        gets(bufWrite, 0);\r\n        if (write(pipe_1[1], bufWrite, strlen(bufWrite)) != strlen(bufWrite)) {\r\n          puts(\"parent - partial\/failed write\");\r\n        }\r\n        do\r\n        {\r\n          memset(bufRead, 0, 200);\r\n          numReada = read(pipe_2[0], bufRead, 200);\r\n          if (bCheckPtrace || checkDebuggerProcessRunning())\r\n          {\r\n            puts(\"Wrong !!!\\n\");\r\n          }\r\n          else if ( !checkStringIsNumber(bufRead) )\r\n          {\r\n            puts(\"Wrong !!!\\n\");\r\n          }\r\n          else\r\n          {\r\n            if ( atoi(bufRead) )\r\n            {\r\n              puts(\"True\");\r\n              if ( close(pipe_1[1]) == -1 )\r\n                exit(1);\r\n              exit(0);\r\n            }\r\n            puts(\"Wrong !!!\\n\");\r\n          }\r\n        }\r\n        while ( numReada == -1 );\r\n      }\r\n    }\r\n\r\n    char user_input[200];\r\n    ssize_t numRead;\r\n\r\n    close(pipe_1[1]);\r\n    close(pipe_2[0]);\r\n\r\n    while ( 1 )\r\n    {\r\n      memset(user_input, 0, 200);\r\n      numRead = read(pipe_1[0], user_input, 200);\r\n      if ( numRead == -1 )\r\n        break;\r\n      if ( numRead )\r\n      {\r\n        if ( childCheckDebugResult() )\r\n        {\r\n          responseFalse();\r\n        }\r\n        else if ( user_input[0] == '{' )\r\n        {\r\n          if ( strlen(user_input) == 42 )\r\n          {\r\n            if ( !strncmp(&user_input[1], \"5 xxxxxx 1\", 10) )\r\n            {\r\n              if ( user_input[strlen(user_input) - 1] == '}' )\r\n              {\r\n                if ( !strncmp(&user_input[31], \"4 xxxxxx d\", 10) )\r\n                {\r\n                  if ( !confuseKey(user_input, 42) )\r\n                  {\r\n                    responseFalse();\r\n                  }\r\n                  else if ( !strncmp(user_input, \"{da xxxxxxxxxxxx CENSORED xxxxxxxxxxxx 8c}\", 42) )\r\n                  {\r\n                    responseTrue();\r\n                  }\r\n                  else\r\n                  {\r\n                    responseFalse();\r\n                  }\r\n                }\r\n                else\r\n                {\r\n                  responseFalse();\r\n                }\r\n              }\r\n              else\r\n              {\r\n                responseFalse();\r\n              }\r\n            }\r\n            else\r\n            {\r\n              responseFalse();\r\n            }\r\n          }\r\n          else\r\n          {\r\n            responseFalse();\r\n          }\r\n        }\r\n        else\r\n        {\r\n          responseFalse();\r\n        }\r\n      }\r\n    }\r\n    exit(1);\r\n\r\n  }\r\n  exit(1);\r\n}<\/pre>\n

The program consists of two processes. The parent prints replies based on the child’s response. Both processes are (at least theoretically) protected against ptrace<\/code>. It could be possible to still debug both, but in this case it won’t be necessary.<\/p>\n

It can clearly be seen that the only answer that is not “wrong<\/em>” is being printed when the child process responds with a nonzero integer.<\/p>\n

if ( atoi(bufRead) )\r\n{\r\n  puts(\"True\");\r\n  if ( close(pipe_1[1]) == -1 )\r\n    exit(1);\r\n  exit(0);\r\n}<\/pre>\n

On the other hand, the child process calls either responseFalse<\/code> or responseTrue<\/code> functions, which in turn respond to the parent with \"0\"<\/code> and \"1\"<\/code> respectively.<\/p>\n

By looking at the following code:<\/p>\n

else if ( user_input[0] == '{' )\r\n{\r\n  if ( strlen(user_input) == 42 )\r\n  {\r\n    if ( !strncmp(&user_input[1], \"5 xxxxxx 1\", 10) )\r\n    {\r\n      if ( user_input[strlen(user_input) - 1] == '}' )\r\n      {\r\n        if ( !strncmp(&user_input[31], \"4 xxxxxx d\", 10) )\r\n        {\r\n          if ( !confuseKey(user_input, 42) )\r\n          {\r\n            responseFalse();\r\n          }\r\n          else if ( !strncmp(user_input, \"{da xxxxxxxxxxxx CENSORED xxxxxxxxxxxx 8c}\", 42) )\r\n          {\r\n            responseTrue();<\/pre>\n

it can be seen that the only path that results in a correct response is if the input:<\/p>\n