Rules & Notes
- MISSION: You should fix vulnerabilities of the given source code, WITHOUT changing its normal behavior.
- RULE0: When an honest user gives a non-malicious (but maybe incorrect) input which does not trigger the vulnerabilities,
the output of uploaded fixed code should be the same as before. - RULE1: When the attacker gives his/her attack vector, your program should not crash or do dangerous actions (explained below),
but continue its execution and exit normally at the end. In this situation, your program is allowed to output anything. - RULE2: A (poorly-tested) source code may crash even when interacting with a normal user. You should fix these cases too.
(NOTE: the output should be correct in this case) - Dangerous actions (stated above) includes buffer overflows, writing to unallocated memory address, reading uninitialized memory,
and any other programming mistakes leading to crash/instability. - Some prevention techniques, detect the attack and prevent memory corruption but throw an exception which terminates the program,
leading to denial of service. You should avoid such termination and the program should recover from the attack, continue execution,
and exit normally at the end.
FIXED CODE:
update: this code is still vulnerable but earned the flag for us.
verifier: http://ctf.sharif.edu:53840/problem.php?problem=ctf5quals_seccoding2
#include <stdio.h> #include <string.h> #include <stdlib.h> void continueHandler(const wchar_t * expression, const wchar_t * function, const wchar_t * file, unsigned int line, uintptr_t pReserved) { // just continue } void safefree(char **ptr) { if (*ptr != NULL) { free(*ptr); *ptr = NULL; } } int main() { char tmp[50]; printf("Line Editor\n"); printf("-----------\n\n"); int size; printf("Line size: "); //============================================================= // set limit for scanf scanf("%3d", &size); // [3-...-9] //============================================================= //============================================================= // exit program if lenght is zero or negative if (size <= 0) return -14; //============================================================= gets_s(tmp, sizeof(tmp)); char *line = (char *)malloc(size + 1); _set_invalid_parameter_handler(continueHandler); restart: line[0] = 0; while (1) { printf("Enter the offset (or \"quit\"): "); gets_s(tmp, sizeof(tmp)); if (!strcmp(tmp, "quit")) { printf("OUTPUT LINE: %s\n\n", line); //============================================================= // After restart ,line(variable) does not exist, and crash occurs on (line[0] = 0) statement // so move [call safefree()] to end of the code // safefree(&line); //============================================================= break; } //============================================================= // use unsigned int instead of int unsigned int offset; //============================================================= if (!(offset = atoi(tmp)) || offset - 1 > (int)strlen(line)) { printf("ERROR\n"); continue; } printf("Enter the text: "); gets_s(tmp, sizeof(tmp)); //============================================================= // Use (strcpy_s) instead (_snprintf_s); to prevent format string attack if (strcpy_s(line + (offset - 1), size - (offset - 1) + 1, tmp) != 0) //============================================================= { printf("ERROR\n"); line[size] = 0; continue; } } printf("Restart (y/n): "); scanf("%s", tmp); if (tmp[0] == 'y') { gets_s(tmp, sizeof(tmp)); goto restart; } //============================================================= safefree(&line); //============================================================= return -14; }