Published: March 5, 2025
86
77
661

Can you spot the bug? The goal is to leak the secret.

Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›

@ifsecure It is written in C. You are welcome! ;)

@carste1n But... but... I like C

@ifsecure Yeah. You canโ€™t compile a jpeg. Classic error

@ifsecure Fix the bug: inline uint32_t *get_element_safe(uint32_t *arr, uint32_t index) { if (index >= SIZE || index < 0) { // Check for both upper and lower bounds return nullptr; } return arr + index; }

Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›

@ifsecure The problem stems from the inline function and depends on which compiler and optimization levels are used. Using max optimization (-O3) on gcc and clang yield different results. gcc correctly checks the index argument, however clang does not. Using no optimization (-O0), both

Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›
Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›

@ifsecure I am not good with C/C++ .. but what is suspicious to me is that get_element_safe accepts a pointer to memory address as first argument. But we are inputting the array object in it, which would actually point to its address in memory now. And if put index above 8, we will

@ifsecure If get_element_safe returns nullptr(because index is out of bounds), the code still attempts to dereference it with printf("Element: %x\n", *element);, which will cause a segmentation fault.

@ifsecure Yes, there is a critical bug in the get_element_safe function that allows for an out-of-bounds read, which can be exploited to leak the contents of secret[].

@ifsecure The newline at the end of the file is missing

@ifsecure No error handling for file < secret.txt> operations.

@ifsecure Enter -8

@ifsecure Does cin and fread?!

@ifsecure 2 fundamental bugs, only one of which will leak the secret. 1) nobody checking return code from "fread" or "fclose" 2) "get_element_safe" is explicitly inline (not that it matters). What matters is that there is no logic protecting the print from the "nullptr" return from it.

@ifsecure Your guardrail isnโ€™t going to work here because itโ€™s always going to get read the data regardless. You need to modify your if statement

@ifsecure First issue: you posted the source on X. Thatโ€™s not very secure.

@ifsecure Pre c++03, if we feed junk to that std::cin it will NOT write to the 'index' var at all. Post compilation 'index' is likely being stored in a register like eax, which will have been reused already in this function a few times (as 'i' and possibly 'fp' and perhaps inside fread()

@ifsecure ez mode, negative indices aren't checked

@ifsecure loop around!

@ifsecure *nullptr is UB, and i guess the compiler might just optimise that check out?

@ifsecure Compilers tend to optimize UB conditions (eg: *nullptr) on the premise theyโ€™re unlikely to take place. If compiled with optimisations, the code path returning nullptr would be eliminated also removing bound checks, unless the return of get_element_safe would be explicitly checked

@ifsecure Since null deref is UB, clang removes the bounds check unless -O0 is used (https://godbolt.org/z/7vcbPPzM... Interestingly, gcc does not exhibit this behavior (https://godbolt.org/z/dd6rsavj...

Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›

@ifsecure dereferencing a null pointer is ub so the compiler removes the if condition when optimizations are on. that will let you read the secret with indices > 8

@ifsecure Dereferencing a null pointer or accessing memory outside the array's bounds triggers undefined behavior in C++, which could be exploited to access unauthorized memory regions, including the secret variable.

@ifsecure I guess the way of taking input of the index variable is vulnerable. It can be negative to read the secret.

@ifsecure The compiler can eliminate the check because the other option leads to UB

@ifsecure people have already replied. if condition is optimised out and with just the correct high value for index read the flag

@ifsecure Kind of spooky how many people are getting this wrong.

@ifsecure Buffer Overflow on arr[] Access uint32_t arr[SIZE]; uint32_t secret[SIZE2]; arr[] and secret[] are stored sequentially in memory. The user input (index) is unchecked for accessing beyond arr[]. If index >= SIZE but still within SIZE2, it accesses secret[], leaking itscontent

@ifsecure These replies are terrifying. At least a couple catch the possible null pointer dereference, but the amount thinking a uint can be negative or relying on AIโ€ฆ real folks writing real code in the real world. ๐Ÿ˜ฐ

@ifsecure For everyone claiming that it doesnโ€™t handle negative values, the variable type is unsigned, so it canโ€™t be negative. What am I missing? However, nullptr UB optimization makes sense.

@ifsecure The compiler will optimize away your checks. Something like this will work

Image in tweet by Ivan Fratric ๐Ÿ’™๐Ÿ’›

@ifsecure oob arr+index if ind is negative

@ifsecure Obviously the bug is syntax highlighting being disabled. Very root cause of every undefined behavior.

Share this thread

Read on Twitter

View original thread

Navigate thread

1/36