Ошибка off by one

From Wikipedia, the free encyclopedia

From Wikipedia, the free encyclopedia

An off-by-one error or off-by-one bug (known by acronyms OBOE, OBO, OB1 and OBOB) is a logic error involving the discrete equivalent of a boundary condition. It often occurs in computer programming when an iterative loop iterates one time too many or too few. This problem could arise when a programmer makes mistakes such as using «is less than or equal to» where «is less than» should have been used in a comparison, or fails to take into account that a sequence starts at zero rather than one (as with array indices in many languages). This can also occur in a mathematical context.

Cases[edit]

Looping over arrays[edit]

Consider an array of items, and items m through n (inclusive) are to be processed. How many items are there? An intuitive answer may be n − m, but that is off by one, exhibiting a fencepost error; the correct answer is
(n – m) + 1.

For this reason, ranges in computing are often represented by half-open intervals; the range from m to n (inclusive) is represented by the range from m (inclusive) to n + 1 (exclusive) to avoid fencepost errors. For example, a loop that iterates five times (from 0 to 4 inclusive) can be written as a half-open interval from 0 to 5:

for (index = 0; index < 5; index++) 
{
    /* Body of the loop */
}

The loop body is executed first of all with index equal to 0; index then becomes 1, 2, 3, and finally 4 on successive iterations. At that point, index becomes 5, so index < 5 is false and the loop ends. However, if the comparison used were <= (less than or equal to), the loop would be carried out six times: index takes the values 0, 1, 2, 3, 4, and 5. Likewise, if index were initialized to 1 rather than 0, there would only be four iterations: index takes the values 1, 2, 3, and 4. Both of these alternatives can cause off-by-one errors.

Another such error can occur if a do-while loop is used in place of a while loop (or vice versa.) A do-while loop is guaranteed to run at least once.

Array-related confusion may also result from differences in programming languages. Numbering from 0 is most common, but some languages start array numbering with 1. Pascal has arrays with user-defined indices. This makes it possible to model the array indices after the problem domain.

Fencepost error[edit]

A straight fence with n sections has n+1 posts.

A fencepost error (occasionally called a telegraph pole, lamp-post, or picket fence error) is a specific type of off-by-one error. An early description of this error appears in the works of Vitruvius.[1] The following problem illustrates the error:

If you build a straight fence 30 feet long with posts spaced 3 feet apart, how many posts do you need?

The common answer of 10 posts is wrong. This response comes from dividing the length of the fence by the spacing apart from each post, with the quotient being erroneously classified as the number of posts. In actuality, the fence has 10 sections and 11 posts.

In this scenario, a fence with n sections will have n + 1 posts. Conversely, if the fence contains n posts, it will contain n − 1 sections. This relationship is important to consider when dealing with the reverse error. The reverse error occurs when the number of posts is known and the number of sections is assumed to be the same. Depending on the design of the fence, this assumption can be correct or incorrect.

The following problem demonstrates the reverse error:

If you have n posts, how many sections are there between them?

The interpretation for the fence’s design changes the answer to this problem. The correct number of sections for a fence is n − 1 if the fence is a free-standing line segment bounded by a post at each of its ends (e.g., a fence between two passageway gaps), n if the fence forms one complete, free-standing loop (e.g., enclosure accessible by surmounting, such as a boxing ring), or n + 1 if posts do not occur at the ends of a line-segment-like fence (e.g., a fence between and wall-anchored to two buildings). The precise problem definition must be carefully considered, as the setup for one situation may give the wrong answer for other situations. Fencepost errors come from counting things rather than the spaces between them, or vice versa, or by neglecting to consider whether one should count one or both ends of a row.

Fencepost errors can also occur in units other than length. For example, the Time Pyramid, consisting of 120 blocks placed at 10-year intervals between blocks, is scheduled to take 1,190 years to build (not 1,200), from the installation of the first block to the last block. One of the earliest fencepost errors involved time, where the Julian calendar originally calculated leap years incorrectly, due to counting inclusively rather than exclusively, yielding a leap year every three years rather than every four.

«Fencepost error» can, in rare occasions, refer to an error induced by unexpected regularities in input values,[2] which can (for instance) completely thwart a theoretically efficient binary tree or hash function implementation. This error involves the difference between expected and worst case behaviours of an algorithm.

In larger numbers, being off by one is often not a major issue. In smaller numbers, however, and specific cases where accuracy is paramount committing an off-by-one error can be disastrous. Sometimes such an issue will also be repeated and, therefore, worsened, by someone passing on an incorrect calculation if the following person makes the same kind of mistake again (of course, the error might also be reversed).

An example of this error can occur in the computational language MATLAB with the linspace() linear interpolation function, whose parameters are (lower value, upper value, number of values) and not (lower value, upper value, number of increments). A programmer who misunderstands the third parameter to be the number of increments might hope that linspace(0,10,5) would achieve a sequence [0, 2, 4, 6, 8, 10] but instead would get [0, 2.5, 5, 7.5, 10].

Security implications[edit]

A common off-by-one error which results in a security-related bug is caused by misuse of the C standard library strncat routine. A common misconception with strncat is that the guaranteed null termination will not write beyond the maximum length. In reality it will write a terminating null character one byte beyond the maximum length specified. The following code contains such a bug:

void foo (char *s) 
{
    char buf[15];
    memset(buf, 0, sizeof(buf));
    strncat(buf, s, sizeof(buf)); // Final parameter should be: sizeof(buf)-1
}

Off-by-one errors are common in using the C library because it is not consistent with respect to whether one needs to subtract 1 byte – functions like fgets() and strncpy will never write past the length given them (fgets() subtracts 1 itself, and only retrieves (length − 1) bytes), whereas others, like strncat will write past the length given them. So the programmer has to remember for which functions they need to subtract 1.

On some systems (little endian architectures in particular) this can result in the overwriting of the least significant byte of the frame pointer. This can cause an exploitable condition where an attacker can hijack the local variables for the calling routine.

One approach that often helps avoid such problems is to use variants of these functions that calculate how much to write based on the total length of the buffer, rather than the maximum number of characters to write. Such functions include strlcat and strlcpy, and are often considered «safer» because they make it easier to avoid accidentally writing past the end of a buffer. (In the code example above, calling strlcat(buf, s, sizeof(buf)) instead would remove the bug.)

See also[edit]

  • Boundary-value analysis
  • Pigeonhole principle
  • Rounding error
  • Zero-based numbering

References[edit]

Citations[edit]

  1. ^ Moniot, Robert K., Who first described the «fence-post error?», Fordham University, archived from the original on 2016-03-05, retrieved 2016-07-07.
  2. ^ Raymond, Eric. «The Jargon File». Retrieved 17 May 2021.

Sources[edit]

  • An earlier version of this article was based on fencepost error at FOLDOC, used with permission.
  • Dijkstra, Edsger Wybe (May 2, 2008). «Why numbering should start at zero (EWD 831)». E. W. Dijkstra Archive. University of Texas at Austin. Retrieved 2011-03-16.
  • In the Common Weakness Enumeration system this issue is listed as CWE-193: Off-by-one Error

Further reading[edit]

  • Parker, Matt (2021). Humble Pi: When Math Goes Wrong in the Real World. Riverhead Books. ISBN 978-0593084694.

From Wikipedia, the free encyclopedia

An off-by-one error or off-by-one bug (known by acronyms OBOE, OBO, OB1 and OBOB) is a logic error involving the discrete equivalent of a boundary condition. It often occurs in computer programming when an iterative loop iterates one time too many or too few. This problem could arise when a programmer makes mistakes such as using «is less than or equal to» where «is less than» should have been used in a comparison, or fails to take into account that a sequence starts at zero rather than one (as with array indices in many languages). This can also occur in a mathematical context.

Cases[edit]

Looping over arrays[edit]

Consider an array of items, and items m through n (inclusive) are to be processed. How many items are there? An intuitive answer may be n − m, but that is off by one, exhibiting a fencepost error; the correct answer is
(n – m) + 1.

For this reason, ranges in computing are often represented by half-open intervals; the range from m to n (inclusive) is represented by the range from m (inclusive) to n + 1 (exclusive) to avoid fencepost errors. For example, a loop that iterates five times (from 0 to 4 inclusive) can be written as a half-open interval from 0 to 5:

for (index = 0; index < 5; index++) 
{
    /* Body of the loop */
}

The loop body is executed first of all with index equal to 0; index then becomes 1, 2, 3, and finally 4 on successive iterations. At that point, index becomes 5, so index < 5 is false and the loop ends. However, if the comparison used were <= (less than or equal to), the loop would be carried out six times: index takes the values 0, 1, 2, 3, 4, and 5. Likewise, if index were initialized to 1 rather than 0, there would only be four iterations: index takes the values 1, 2, 3, and 4. Both of these alternatives can cause off-by-one errors.

Another such error can occur if a do-while loop is used in place of a while loop (or vice versa.) A do-while loop is guaranteed to run at least once.

Array-related confusion may also result from differences in programming languages. Numbering from 0 is most common, but some languages start array numbering with 1. Pascal has arrays with user-defined indices. This makes it possible to model the array indices after the problem domain.

Fencepost error[edit]

A straight fence with n sections has n+1 posts.

A fencepost error (occasionally called a telegraph pole, lamp-post, or picket fence error) is a specific type of off-by-one error. An early description of this error appears in the works of Vitruvius.[1] The following problem illustrates the error:

If you build a straight fence 30 feet long with posts spaced 3 feet apart, how many posts do you need?

The common answer of 10 posts is wrong. This response comes from dividing the length of the fence by the spacing apart from each post, with the quotient being erroneously classified as the number of posts. In actuality, the fence has 10 sections and 11 posts.

In this scenario, a fence with n sections will have n + 1 posts. Conversely, if the fence contains n posts, it will contain n − 1 sections. This relationship is important to consider when dealing with the reverse error. The reverse error occurs when the number of posts is known and the number of sections is assumed to be the same. Depending on the design of the fence, this assumption can be correct or incorrect.

The following problem demonstrates the reverse error:

If you have n posts, how many sections are there between them?

The interpretation for the fence’s design changes the answer to this problem. The correct number of sections for a fence is n − 1 if the fence is a free-standing line segment bounded by a post at each of its ends (e.g., a fence between two passageway gaps), n if the fence forms one complete, free-standing loop (e.g., enclosure accessible by surmounting, such as a boxing ring), or n + 1 if posts do not occur at the ends of a line-segment-like fence (e.g., a fence between and wall-anchored to two buildings). The precise problem definition must be carefully considered, as the setup for one situation may give the wrong answer for other situations. Fencepost errors come from counting things rather than the spaces between them, or vice versa, or by neglecting to consider whether one should count one or both ends of a row.

Fencepost errors can also occur in units other than length. For example, the Time Pyramid, consisting of 120 blocks placed at 10-year intervals between blocks, is scheduled to take 1,190 years to build (not 1,200), from the installation of the first block to the last block. One of the earliest fencepost errors involved time, where the Julian calendar originally calculated leap years incorrectly, due to counting inclusively rather than exclusively, yielding a leap year every three years rather than every four.

«Fencepost error» can, in rare occasions, refer to an error induced by unexpected regularities in input values,[2] which can (for instance) completely thwart a theoretically efficient binary tree or hash function implementation. This error involves the difference between expected and worst case behaviours of an algorithm.

In larger numbers, being off by one is often not a major issue. In smaller numbers, however, and specific cases where accuracy is paramount committing an off-by-one error can be disastrous. Sometimes such an issue will also be repeated and, therefore, worsened, by someone passing on an incorrect calculation if the following person makes the same kind of mistake again (of course, the error might also be reversed).

An example of this error can occur in the computational language MATLAB with the linspace() linear interpolation function, whose parameters are (lower value, upper value, number of values) and not (lower value, upper value, number of increments). A programmer who misunderstands the third parameter to be the number of increments might hope that linspace(0,10,5) would achieve a sequence [0, 2, 4, 6, 8, 10] but instead would get [0, 2.5, 5, 7.5, 10].

Security implications[edit]

A common off-by-one error which results in a security-related bug is caused by misuse of the C standard library strncat routine. A common misconception with strncat is that the guaranteed null termination will not write beyond the maximum length. In reality it will write a terminating null character one byte beyond the maximum length specified. The following code contains such a bug:

void foo (char *s) 
{
    char buf[15];
    memset(buf, 0, sizeof(buf));
    strncat(buf, s, sizeof(buf)); // Final parameter should be: sizeof(buf)-1
}

Off-by-one errors are common in using the C library because it is not consistent with respect to whether one needs to subtract 1 byte – functions like fgets() and strncpy will never write past the length given them (fgets() subtracts 1 itself, and only retrieves (length − 1) bytes), whereas others, like strncat will write past the length given them. So the programmer has to remember for which functions they need to subtract 1.

On some systems (little endian architectures in particular) this can result in the overwriting of the least significant byte of the frame pointer. This can cause an exploitable condition where an attacker can hijack the local variables for the calling routine.

One approach that often helps avoid such problems is to use variants of these functions that calculate how much to write based on the total length of the buffer, rather than the maximum number of characters to write. Such functions include strlcat and strlcpy, and are often considered «safer» because they make it easier to avoid accidentally writing past the end of a buffer. (In the code example above, calling strlcat(buf, s, sizeof(buf)) instead would remove the bug.)

See also[edit]

  • Boundary-value analysis
  • Pigeonhole principle
  • Rounding error
  • Zero-based numbering

References[edit]

Citations[edit]

  1. ^ Moniot, Robert K., Who first described the «fence-post error?», Fordham University, archived from the original on 2016-03-05, retrieved 2016-07-07.
  2. ^ Raymond, Eric. «The Jargon File». Retrieved 17 May 2021.

Sources[edit]

  • An earlier version of this article was based on fencepost error at FOLDOC, used with permission.
  • Dijkstra, Edsger Wybe (May 2, 2008). «Why numbering should start at zero (EWD 831)». E. W. Dijkstra Archive. University of Texas at Austin. Retrieved 2011-03-16.
  • In the Common Weakness Enumeration system this issue is listed as CWE-193: Off-by-one Error

Further reading[edit]

  • Parker, Matt (2021). Humble Pi: When Math Goes Wrong in the Real World. Riverhead Books. ISBN 978-0593084694.

From Wikipedia, the free encyclopedia

An off-by-one error or off-by-one bug (known by acronyms OBOE, OBO, OB1 and OBOB) is a logic error involving the discrete equivalent of a boundary condition. It often occurs in computer programming when an iterative loop iterates one time too many or too few. This problem could arise when a programmer makes mistakes such as using «is less than or equal to» where «is less than» should have been used in a comparison, or fails to take into account that a sequence starts at zero rather than one (as with array indices in many languages). This can also occur in a mathematical context.

Cases[edit]

Looping over arrays[edit]

Consider an array of items, and items m through n (inclusive) are to be processed. How many items are there? An intuitive answer may be n − m, but that is off by one, exhibiting a fencepost error; the correct answer is
(n – m) + 1.

For this reason, ranges in computing are often represented by half-open intervals; the range from m to n (inclusive) is represented by the range from m (inclusive) to n + 1 (exclusive) to avoid fencepost errors. For example, a loop that iterates five times (from 0 to 4 inclusive) can be written as a half-open interval from 0 to 5:

for (index = 0; index < 5; index++) 
{
    /* Body of the loop */
}

The loop body is executed first of all with index equal to 0; index then becomes 1, 2, 3, and finally 4 on successive iterations. At that point, index becomes 5, so index < 5 is false and the loop ends. However, if the comparison used were <= (less than or equal to), the loop would be carried out six times: index takes the values 0, 1, 2, 3, 4, and 5. Likewise, if index were initialized to 1 rather than 0, there would only be four iterations: index takes the values 1, 2, 3, and 4. Both of these alternatives can cause off-by-one errors.

Another such error can occur if a do-while loop is used in place of a while loop (or vice versa.) A do-while loop is guaranteed to run at least once.

Array-related confusion may also result from differences in programming languages. Numbering from 0 is most common, but some languages start array numbering with 1. Pascal has arrays with user-defined indices. This makes it possible to model the array indices after the problem domain.

Fencepost error[edit]

A straight fence with n sections has n+1 posts.

A fencepost error (occasionally called a telegraph pole, lamp-post, or picket fence error) is a specific type of off-by-one error. An early description of this error appears in the works of Vitruvius.[1] The following problem illustrates the error:

If you build a straight fence 30 feet long with posts spaced 3 feet apart, how many posts do you need?

The common answer of 10 posts is wrong. This response comes from dividing the length of the fence by the spacing apart from each post, with the quotient being erroneously classified as the number of posts. In actuality, the fence has 10 sections and 11 posts.

In this scenario, a fence with n sections will have n + 1 posts. Conversely, if the fence contains n posts, it will contain n − 1 sections. This relationship is important to consider when dealing with the reverse error. The reverse error occurs when the number of posts is known and the number of sections is assumed to be the same. Depending on the design of the fence, this assumption can be correct or incorrect.

The following problem demonstrates the reverse error:

If you have n posts, how many sections are there between them?

The interpretation for the fence’s design changes the answer to this problem. The correct number of sections for a fence is n − 1 if the fence is a free-standing line segment bounded by a post at each of its ends (e.g., a fence between two passageway gaps), n if the fence forms one complete, free-standing loop (e.g., enclosure accessible by surmounting, such as a boxing ring), or n + 1 if posts do not occur at the ends of a line-segment-like fence (e.g., a fence between and wall-anchored to two buildings). The precise problem definition must be carefully considered, as the setup for one situation may give the wrong answer for other situations. Fencepost errors come from counting things rather than the spaces between them, or vice versa, or by neglecting to consider whether one should count one or both ends of a row.

Fencepost errors can also occur in units other than length. For example, the Time Pyramid, consisting of 120 blocks placed at 10-year intervals between blocks, is scheduled to take 1,190 years to build (not 1,200), from the installation of the first block to the last block. One of the earliest fencepost errors involved time, where the Julian calendar originally calculated leap years incorrectly, due to counting inclusively rather than exclusively, yielding a leap year every three years rather than every four.

«Fencepost error» can, in rare occasions, refer to an error induced by unexpected regularities in input values,[2] which can (for instance) completely thwart a theoretically efficient binary tree or hash function implementation. This error involves the difference between expected and worst case behaviours of an algorithm.

In larger numbers, being off by one is often not a major issue. In smaller numbers, however, and specific cases where accuracy is paramount committing an off-by-one error can be disastrous. Sometimes such an issue will also be repeated and, therefore, worsened, by someone passing on an incorrect calculation if the following person makes the same kind of mistake again (of course, the error might also be reversed).

An example of this error can occur in the computational language MATLAB with the linspace() linear interpolation function, whose parameters are (lower value, upper value, number of values) and not (lower value, upper value, number of increments). A programmer who misunderstands the third parameter to be the number of increments might hope that linspace(0,10,5) would achieve a sequence [0, 2, 4, 6, 8, 10] but instead would get [0, 2.5, 5, 7.5, 10].

Security implications[edit]

A common off-by-one error which results in a security-related bug is caused by misuse of the C standard library strncat routine. A common misconception with strncat is that the guaranteed null termination will not write beyond the maximum length. In reality it will write a terminating null character one byte beyond the maximum length specified. The following code contains such a bug:

void foo (char *s) 
{
    char buf[15];
    memset(buf, 0, sizeof(buf));
    strncat(buf, s, sizeof(buf)); // Final parameter should be: sizeof(buf)-1
}

Off-by-one errors are common in using the C library because it is not consistent with respect to whether one needs to subtract 1 byte – functions like fgets() and strncpy will never write past the length given them (fgets() subtracts 1 itself, and only retrieves (length − 1) bytes), whereas others, like strncat will write past the length given them. So the programmer has to remember for which functions they need to subtract 1.

On some systems (little endian architectures in particular) this can result in the overwriting of the least significant byte of the frame pointer. This can cause an exploitable condition where an attacker can hijack the local variables for the calling routine.

One approach that often helps avoid such problems is to use variants of these functions that calculate how much to write based on the total length of the buffer, rather than the maximum number of characters to write. Such functions include strlcat and strlcpy, and are often considered «safer» because they make it easier to avoid accidentally writing past the end of a buffer. (In the code example above, calling strlcat(buf, s, sizeof(buf)) instead would remove the bug.)

See also[edit]

  • Boundary-value analysis
  • Pigeonhole principle
  • Rounding error
  • Zero-based numbering

References[edit]

Citations[edit]

  1. ^ Moniot, Robert K., Who first described the «fence-post error?», Fordham University, archived from the original on 2016-03-05, retrieved 2016-07-07.
  2. ^ Raymond, Eric. «The Jargon File». Retrieved 17 May 2021.

Sources[edit]

  • An earlier version of this article was based on fencepost error at FOLDOC, used with permission.
  • Dijkstra, Edsger Wybe (May 2, 2008). «Why numbering should start at zero (EWD 831)». E. W. Dijkstra Archive. University of Texas at Austin. Retrieved 2011-03-16.
  • In the Common Weakness Enumeration system this issue is listed as CWE-193: Off-by-one Error

Further reading[edit]

  • Parker, Matt (2021). Humble Pi: When Math Goes Wrong in the Real World. Riverhead Books. ISBN 978-0593084694.

Уязвимость «off-by-one» (завышение/занижение на единицу) – это достаточно старая проблема. Вот перевод описания из английской версии Википедии:


Ошибка off-by-one (off-by-one error, OBOE) это логическая ошибка, возникающая при использовании дискретного эквивалента граничных условий. Подобные ошибки нередки в компьютерном программировании, когда цикл итерации повторяется на один раз больше или меньше, чем следует. Как правило, проблема возникает, если программист не учитывает, что последовательность начинается с нуля, а не с единицы (как, например, с индексами массивов в некоторых языках программирования) или ошибочно использует в сравнении «меньше или равно» вместо «меньше».

Подобные ошибки позволяют проводить DoS-атаки или даже выполнять произвольный код. В интернете есть множество ресурсов, на которых объясняется, как эксплуатировать «переполнение кучи на одну позицию» (“off-by-one heap overflow”).

Но почему «Ошибка на одну позицию 2.0»?

Читая свою ленту на Твиттере, я заметил нечто весьма интересное. Сообщение (tweet), отправленное с официального корпоративного аккаунта, содержало сокращенную ссылку (bit.ly), которая вела на сайт, распространяющий потенциально опасное приложение.

Если внимательно посмотреть на снимок экрана, обнаружатся две похожие ссылки, сокращенные с помощью сервиса bit.ly. В одной из них пропущена буква d. Отсюда и название – «Ошибка на одну позицию 2.0».

В результате элементарной ошибки копирования новая ссылка ведет совершенно не на тот сайт, на который должна была бы. На всякий случай я решил проверить ссылку на сайте http://web-sniffer.net.

Вот сайт, на который попадаешь по ссылке в сообщении Twitter:

Судя по присутствию слова quiz в названии сайта (LOLquiz), он предлагает разного рода викторины. Однако выглядит он подозрительно. По моему опыту, многие сайты, похожие на этот, используются для вредоносных целей.

Поэтому я решил продолжить расследование и кликнул по ссылке на выбранную случайным образом викторину:

Войдя в тестовый аккаунт Twitter на тестовом компьютере, я кликнул по кнопке подтверждения участия в викторине. На той же странице было написано, что регистрация означает согласие на подписку на ленту сообщений в Twitter, принадлежащую владельцам сайта.
Удивительно, но, пройдя по ссылке, я снова оказался в Twitter, и мне было предложено разрешить некому приложению доступ к моей учетной записи, как видно на снимке экрана ниже:

В своей тестовой учетной записи я авторизовал приложение и был перенаправлен на ту самую викторину, в которой собирался принять участие:

Но каковы были функции того приложения?

Разрешив установку этого приложения, я тем самым предоставил ему права на чтение и запись моего аккаунта в Twitter, как видно на снимке экрана ниже:

Как только приложение получило доступ к моему аккаунту, оно автоматически подписалось на ленту учетной записи lolquiz в Twitter. Эта особенность поведения программы описана на сайте одним предложением, набранным очень мелким шрифтом, и при первом просмотре сайта я его не заметил.

Теперь мой тестовый аккаунт «следует» в Twitter за авторами этого потенциально опасного приложения.

Если посмотреть на число подписчиков на сообщения этой учетной записи, окажется, что права доступа к своим аккаунтам дали этому приложению более 300 000(!) пользователей. Я уверен, что большинство из них не читали набранную мелким шрифтом информацию о функции этого приложения по автоматической подписке на ленту сообщений в Twitter, принадлежащую владельцам сайта.

Пока что никаких сообщений не было. Поэтому я решил попробовать ответить на вопросы викторины и посмотреть, произойдет ли что-нибудь после этого:

Как только вы заканчиваете отвечать на вопросы, приложение рассылает подписчикам вашего аккаунта сообщение с вашими результатами. Если кто-то из них захочет попробовать принять участие в викторине, ему тоже придется дать приложению доступ к своей учетной записи в Twitter, и он тоже автоматически станет подписчиком «lolquiz» и разошлет сообщение о своих результатах своим подписчикам и т.д. Это приводит к вирусному распространению приложения.

Интересно, что автор этого приложения сам является подписчиком двух аналогичных лент в Twitter.

Простой поиск на Twitter выдает множество аналогичных сообщений от других пользователей:

Остается непонятной настоящая цель, ради которой создавалось это приложение, которое (на данный момент) является не вредоносным, но потенциально опасным.

Авторы приложения утверждают, что вы всегда можете отписаться от их ленты сообщений, но не упоминают о том факте, что при этом у приложения сохранятся права на чтение и запись в вашей ленте Twitter. Отписаться от их ленты можно, отправив им сообщение напрямую (Direct Message), но это не приводит к удалению приложения или к прекращению автоматической рассылки сообщений.

Подобные приложения-викторины очень распространены в сети Facebook, а теперь они, очевидно, заполонили и Twitter. Эта викторина, судя по всему, появилась в 2009 году.

Если авторы приложения решат разместить на сайте что-то более опасное (или если он будет взломан с размещением вредоносных ссылок), это может привести к куда более серьезной проблеме, которая затронет сотни тысяч пользователей. Ведь авторы приложения могут посылать какие угодно сообщения с вашего аккаунта в Twitter.

Мой пост о фальшивом антивирусе, распространяемом через Twitter, дает прекрасный пример того, что может произойти.

Мне кажется, это со всей очевидностью показывает, насколько опасными могут быть сервисы по сокращению интернет-адресов: банальная ошибка копирования текста может привести к тому, что по ссылке будет открываться совершенно другой веб-сайт, в то время как при использовании обычных ссылок в большинстве случаев подобная ошибка приведет лишь к сообщению «404 – Страница не найдена».

Содержание

  1. Off-By-One Errors In Swift Programming
  2. Table of Contents
  3. What’s An Off-By-One Error?
  4. Further Reading
  5. Off-By-One in the heap¶
  6. Introduction¶
  7. off-by-one Vulnerability Principle¶
  8. off-by-one Use ideas¶
  9. Example 1¶
  10. Example 2¶
  11. 实例 1: Asis CTF 2016 b00ks¶
  12. Title introduction¶
  13. create¶
  14. Vulnerability¶
  15. off-by-one Override pointer low byte¶
  16. Using the stack to achieve utilization¶
  17. exploit¶
  18. Simple plan¶
  19. Instance 2 : plaidctf 2015 plaiddb¶
  20. Functional Analysis¶
  21. Exploit Analysis¶
  22. exploit¶

Off-By-One Errors In Swift Programming

Off by one errors, like “Array index out of range”, happen in programming when we’ve got the boundaries of things wrong. In this tutorial, you’ll learn what an off-by-one error is and how you can solve it with Swift programming.

Here’s what we’ll get into:

  • What an off-by-one error is and how to solve it
  • Swift’s dreaded Array index out of range error
  • Why the fencepost problem is crucial to understand
  • Approaches to find and solve the OBOE in Swift
  • Including mandatory puns about being off by one…

Table of Contents

What’s An Off-By-One Error?

A popular quote from Jeff Atwood, author of Coding Horror, is this:

There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Off-by-one errors (OBOEs) happen when a loop iterates one time too many, or one too few. These errors can also happen when an array is zero-indexed, and you assume that it starts at 1. An off-by-one error is considered a boundary problem, that is, a problem that occurs around the boundaries of a set of data.

Let’s take a look at an example. Imagine we’re working on a bit of code, and we want to create a loop that iterates some code exactly 5 times.

for i in 0…5 <
print(i)
>

Run the above code. What happens? For some reason – accidentally or otherwise – we’ve erroneously started counting our loop at 0. Because we’ve used the closed range operator … with 0 and 5, our loop iterates from 0 to 5, including 5. As such, the number of times the loop iterates is… 6!

It’s not likely that you make such a mistake deliberately, so the code example is a bit contrived. Consider however what happens to the loop when you change the following bits of code:

  • 0 into 1 — how many iterations do you get?
  • … into ..
  • Conditional loops can use , or =, and they differ

Based on those principles, you’re equipped to tackle any off-by-one error that comes your way. Does your code accidentally skip the last item in an array? Are you trying to access a post-last array item that doesn’t exist? Is the outcome of your algorithm always off by one? Check the above syntax and principles, and chances are that you’ll find that off-by-one error.

Further Reading

In this tutorial, we’ve discussed a common cause of bugs in programming: the off-by-one error, or OBOE. As it turns out, it’s easy to accidentally incorporate this bug into your code. Fortunately, it’s quite easy to solve, too. Awesome!

And of course, we can also just joke around, admit that we make mistakes, and remind ourselves that off-by-one errors just happen:

There are two kinds of people in the world. 1. People who understand off-by-one errors.

Источник

Off-By-One in the heap¶

Introduction¶

Strictly speaking, the off-by-one vulnerability is a special type of overflow vulnerability. Off-by-one means that when a program writes to a buffer, the number of bytes written exceeds the number of bytes requested by the buffer itself. And only one byte is crossed.

off-by-one Vulnerability Principle¶

Off-by-one refers to a single-byte buffer overflow. This vulnerability is often related to the lack of strict boundary verification and string operations. Of course, it does not rule out that the size of the write is just one byte more. Where the boundary verification is not strict, usually includes

  • When writing data to a heap block using a loop statement, the number of loops set incorrectly (which is common in C language beginners) results in more than one byte being written.
  • String operation is not appropriate

In general, single-byte overflows are considered to be difficult to exploit, but because of the looseness of Linux’s heap management mechanism ptmalloc validation, Linux-based off-by-one exploits are not complex and powerful. In addition, the point to note is that off-by-one can be based on various buffers, such as stacks, bss segments, etc., but the heap-based off-by-one is more common in CTFs. We will only discuss the off-by-one situation on the heap here.

off-by-one Use ideas¶

  1. The overflow byte is any byte that can be controlled: by modifying the size, there is overlap between the block structures, thereby leaking other block data or overwriting other block data. You can also use the NULL byte overflow method.
  2. The overflow byte is NULL. When the size is 0x100, overflowing the NULL byte makes the prev_in_use bit clear, so the previous block is considered a free block. (1) At this point you can choose to use the unlink method (see the unlink section) for processing. (2) In addition, when the prev_size field is enabled, you can forge prev_size , causing overlap between blocks. The key to this method is that unlink does not check whether the last block of the block found by prev_size (theoretically the block currently unlinked) is equal to the block size currently being unlinked.

In the latest version of the code, the check for the latter method in 2 has been added, but the check was not available before 2.28.

Example 1¶

Our own my_gets function caused an off-by-one vulnerability because the boundaries of the for loop were not controlled enough to cause writes to be executed once, which is also called a fence error.

> Fence errors (sometimes called pole errors or lamppost errors) are a type of error. Such as the following questions:

> Build a straight fence (ie no circle), 30 meters long, 3 meters apart between each fence column, how many fence posts do you need?

> The easiest answer 10 is wrong. This fence has 10 intervals and 11 fence posts.

We use gdb to debug the program. Before inputting, we can see that the two allocated user areas are 16-byte heap blocks.

When we execute my_gets for input, we can see that the data has overflowed to cover the prev_size field of the next heap. print ‘A’*17

Example 2¶

The second common scenario that causes off-by-one is string manipulation. The common reason is that the end of the string is incorrectly calculated.

At first glance, the program doesn’t seem to have any problems (regardless of stack overflow), and many people may write it in the actual code as well. However, the behavior of strlen and strcpy is inconsistent, which leads to the occurrence of off-by-one. Strlen is a function we are familiar with calculating the length of an ascii string. This function does not count the terminator ‘x00’ when calculating the length of a string, but strcpy copies the terminator when copying a string. ‘x00’`. This caused us to write 25 bytes to chunk1, which we can see with gdb debugging.

Execute strcpy after we type ‘A’*24

You can see that the low byte of the size field of the next chunk is overwritten by the terminator ‘x00’ . This branch of the off-by-one is called NULL byte off-by-one, which we will see later. The difference between off-by-one and NULL byte off-by-one. There is still one thing why the low byte is overwritten, because the byte order of the CPU we usually use is small endian, such as a DWORD value stored in the memory using the little endian method.

实例 1: Asis CTF 2016 b00ks¶

Title introduction¶

The topic is a common menu-style program that features a library management system.

The program provides the ability to create, delete, edit, and print books. The title is a 64-bit program and the protection is as follows.

Each time a program creates a program, it allocates a 0x20 byte structure to maintain its information.

create¶

Name and description exist in the book structure, and name and description are allocated on the heap. First allocate the name buffer, use malloc, the size is custom but less than 32.

The description is then assigned, the same size is customizable but unlimited.

After allocating the memory of the book structure

Vulnerability¶

There is a null byte off-by-one vulnerability in the read function of the program. If you look closely at the read function, you can find that the consideration of the boundary is not appropriate.

Because the my_read function in the program has a null byte off-by-one , in fact the terminator ‘x00’ read by my_read is written to 0x555555756060. This will overwrite the terminator ‘x00’ when 0x555555756060

0x555555756068 is written to the book pointer, so there is a vulnerability in the address leak. The value of the first item in the pointer array can be obtained by printing the author name.

In order to achieve the leak, first enter 32 bytes in the author name to make the terminator overwritten. After that we create book1, the pointer of book1 will overwrite the last NULL byte in author name, so that the pointer is directly connected with author name, so that the output author name can get a heap pointer.

off-by-one Override pointer low byte¶

The change function is also provided in the program. The change function is used to modify the author name, so the change can be used to write the author name, and the off-by-one is used to override the low byte of the first item of the pointer array.

After overwriting the low byte of the book1 pointer, this pointer points to the description of book1. Since the program provides the edit function, the content in the description can be arbitrarily modified. We can pre-define the data in the description to create a book structure. The description and name pointers of this book structure can be directly controlled.

Here, the book is forged in the description, and the data used is p64(0x1)+p64(addr)+p64(addr)+pack(0xffff). Where addr+58 is to point the pointer to the pointer address of book2, so that we can modify these pointer values arbitrarily.

Using the stack to achieve utilization¶

Through the previous two parts, we have obtained the ability to read and write at any address. The reader may find that the following operations are obvious, such as writing the get table hijacking process or writing the __malloc_hook hijacking process. But the special thing about this topic is that PIE is turned on and there is no way to leak the libc base address, so we need to think about other methods.

The clever thing about this is that when you allocate a second book, use a large size to make the heap expand in mmap mode. We know that there are two ways to expand the heap. One is that brk will directly expand the original heap, and the other is that mmap will map a piece of memory separately.

Here we apply for an oversized block to extend memory using mmap. Because the memory allocated by mmap has a fixed offset from libc, the base address of libc can be derived.

exploit¶

Simple plan¶

After any read and write, another way to find libc is to first cause the libc address to be written on the heap before any read and write, and then read it out by any read.

In order to find the offset where libc is located, you can debug directly through gdb to view the location of the specific libc address on the heap, without deliberate calculation.

Exp is as follows:

Instance 2 : plaidctf 2015 plaiddb¶

As you can see, the program is 64-bit dynamically linked. The protection is all turned on.

Functional Analysis¶

Key data structure:

The structure of the binary tree is mainly used to store data, and the specific storage process does not affect the utilization.

The function function needs to pay attention to getline (self-implemented single-line read function):

Several main features:

Both dump and get are used to read the content, so key and specific data content can be read, and less attention is needed. Focus on put and del :

The distribution process is:

Malloc (0x38) (structure) 2. getline (malloc 和 realloc)

  1. malloc (size) controllable size
  2. Read the size byte content

The more complicated part we can see later will be used, that is, the part about free used in put

For deletion, this function is more complicated and will not be explained in detail. In fact, you only need to know that he is deleted according to the key, and the key is read using getline . If there is no such key, the part of getline will not be deleted. If any, then free

Exploit Analysis¶

The location of the vulnerability has been pointed out in the functional analysis, in getline , but the special feature of this function is that its allocated size is gradually increasing, by increasing the available size by two, using realloc , that is, if we want to trigger this vulnerability, we need to meet certain size requirements.

According to the allocation process, the size of the satisfaction is:

These sizes can trigger an overflow.

Now we need to know the specific methods we need to adopt. First, the off-by-one vulnerability can cause heap crossover, which can cause the libc address to leak. Afterwards, the utilization method to be used, because there is already a heap crossover, that is, a UAF can be formed, and the UAF common method can be used.

The easiest way to get a UAF vulnerability is of course fastbin attack, so I used fastbin attack.

Here, we can begin to think about how to form the conditions of use we need. The final effect of off-by-one is that you can release a smallbin chunk or unsortedbin chunk of a released state until it is merged into a large chunk by the overflow chunk. That is:

After the use of off-by-one , the chunks that appear above will be merged into a freed chunk. If the position of any intermediate chunk is already allocated, it can cause overlap.

According to our utilization ideas, combined with the topic getline function through malloc(8) and then realloc , we need to:

  1. At least one chunk of any chunk location has been allocated, and the chunk of data can be read to leak the libc address.
  2. The chunk that overflows needs to be allocated before the top chunk, otherwise malloc(8) will be allocated to the top instead of where the chunk should be.
  3. Any chunk location needs at least one chunk that has been released and has a size of 0x71 for fastbin attack
  4. All chunks should not be merged into top, so there should be an already allocated chunk at the bottom to guarantee the distance from the top chunk.
  5. The size of the chunk that overflows should belong to unsortedbin or smallbin. It cannot be fastbin. Otherwise, after being released, according to the allocation method of getline , malloc(8) cannot be allocated at this location.

According to the above principles, we can think about the distribution of chunks as follows:

Since the allocation process has some additional structure (the allocation of the structure itself and getline ), we need to release enough fastbin chunks to avoid the allocation of the structure itself affecting our process.

After that, release 5, 3, 1, and then use delline when del is input, fill 3, causing off-by-one , then merge 4 free to merge (forgery prev_size ), so there is a cross heap structure.

The process is much simpler. First allocate the size of 1 so that the libc address is written to 2, you can leak the address, then allocate 5 and write the required content, you can fastbin attack.

exploit¶

Since the original libc is 2.19 version, loading some strange problems is more troublesome, and this problem does not use the unique features of 2.19, so I used the 2.23 libc for debugging, the version is ubuntu10.

本页面的全部内容在 CC BY-NC-SA 4.0 协议之条款下提供,附加条款亦可能应用。

Источник

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Ошибка ods9013e odis
  • Ошибка not catch checkpoint miflash
  • Ошибка ods2508f odis
  • Ошибка not authenticated with minecraft net
  • Ошибка nonetype object has no attribute id

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии