행복한 프로그래밍

GPT4의 핸드레이 실력 (feat. 드림핵의 종말)

영웅*^%&$ 2023. 6. 14. 12:57
728x90

아래 내용의 대부분 핵심 내용은 gpt4가 작성하였음을 미리 밝힙니다

0x0000000000400771 <+0>: push rbp

0x0000000000400772 <+1>: mov rbp,rsp

0x0000000000400775 <+4>: push r15

0x0000000000400777 <+6>: push r14

0x0000000000400779 <+8>: push r13

0x000000000040077b <+10>: push r12

0x000000000040077d <+12>: sub rsp,0x60

0x0000000000400781 <+16>: mov DWORD PTR [rbp-0x74],edi

0x0000000000400784 <+19>: mov QWORD PTR [rbp-0x80],rsi

0x0000000000400788 <+23>: mov rax,QWORD PTR [rip+0x2008c1] # 0x601050 <stdout@@GLIBC_2.2.5>

0x000000000040078f <+30>: mov esi,0x0

0x0000000000400794 <+35>: mov rdi,rax

0x0000000000400797 <+38>: call 0x400560 <setbuf@plt>

0x000000000040079c <+43>: call 0x400570 <getegid@plt>

0x00000000004007a1 <+48>: mov DWORD PTR [rbp-0x2c],eax

0x00000000004007a4 <+51>: mov edx,DWORD PTR [rbp-0x2c]

0x00000000004007a7 <+54>: mov ecx,DWORD PTR [rbp-0x2c]

0x00000000004007aa <+57>: mov eax,DWORD PTR [rbp-0x2c]

0x00000000004007ad <+60>: mov esi,ecx

0x00000000004007af <+62>: mov edi,eax

0x00000000004007b1 <+64>: mov eax,0x0

0x00000000004007b6 <+69>: call 0x400550 <setresgid@plt>

0x00000000004007bb <+74>: mov QWORD PTR [rbp-0x38],0x1b

0x00000000004007c3 <+82>: movabs rax,0x20656d6f636c6557

0x00000000004007cd <+92>: movabs rdx,0x636520796d206f74

0x00000000004007d7 <+102>: mov QWORD PTR [rbp-0x70],rax

0x00000000004007db <+106>: mov QWORD PTR [rbp-0x68],rdx

0x00000000004007df <+110>: movabs rax,0x6576726573206f68

0x00000000004007e9 <+120>: mov QWORD PTR [rbp-0x60],rax

0x00000000004007ed <+124>: mov WORD PTR [rbp-0x58],0x2172

0x00000000004007f3 <+130>: mov BYTE PTR [rbp-0x56],0x0

0x00000000004007f7 <+134>: mov rax,QWORD PTR [rbp-0x38]

0x00000000004007fb <+138>: mov rdx,rax

0x00000000004007fe <+141>: sub rdx,0x1

0x0000000000400802 <+145>: mov QWORD PTR [rbp-0x40],rdx

0x0000000000400806 <+149>: mov r14,rax

0x0000000000400809 <+152>: mov r15d,0x0

0x000000000040080f <+158>: mov r12,rax

0x0000000000400812 <+161>: mov r13d,0x0

0x0000000000400818 <+167>: mov edx,0x10

0x000000000040081d <+172>: sub rdx,0x1

0x0000000000400821 <+176>: add rax,rdx

0x0000000000400824 <+179>: mov ecx,0x10

0x0000000000400829 <+184>: mov edx,0x0

0x000000000040082e <+189>: div rcx

0x0000000000400831 <+192>: imul rax,rax,0x10

0x0000000000400835 <+196>: sub rsp,rax

0x0000000000400838 <+199>: mov rax,rsp

0x000000000040083b <+202>: add rax,0x0

0x000000000040083f <+206>: mov QWORD PTR [rbp-0x48],rax

0x0000000000400843 <+210>: mov QWORD PTR [rbp-0x28],0x0

0x000000000040084b <+218>: jmp 0x400880 <main+271>

0x000000000040084d <+220>: lea rdx,[rbp-0x70]

0x0000000000400851 <+224>: mov rax,QWORD PTR [rbp-0x28]

0x0000000000400855 <+228>: add rax,rdx

0x0000000000400858 <+231>: movzx eax,BYTE PTR [rax]

0x000000000040085b <+234>: movsx eax,al

0x000000000040085e <+237>: mov rdx,QWORD PTR [rbp-0x28]

0x0000000000400862 <+241>: mov rsi,rdx

0x0000000000400865 <+244>: mov edi,eax

0x0000000000400867 <+246>: call 0x400677 <convert_case>

0x000000000040086c <+251>: mov ecx,eax

0x000000000040086e <+253>: mov rdx,QWORD PTR [rbp-0x48]

0x0000000000400872 <+257>: mov rax,QWORD PTR [rbp-0x28]

0x0000000000400876 <+261>: add rax,rdx

0x0000000000400879 <+264>: mov BYTE PTR [rax],cl

0x000000000040087b <+266>: add QWORD PTR [rbp-0x28],0x1

0x0000000000400880 <+271>: mov rax,QWORD PTR [rbp-0x28]

0x0000000000400884 <+275>: cmp rax,QWORD PTR [rbp-0x38]

0x0000000000400888 <+279>: jb 0x40084d <main+220>

0x000000000040088a <+281>: mov rax,QWORD PTR [rbp-0x48]

0x000000000040088e <+285>: mov rdi,rax

0x0000000000400891 <+288>: call 0x400540 <puts@plt>

0x0000000000400896 <+293>: mov eax,0x0

0x000000000040089b <+298>: call 0x4006d8 <do_stuff>

0x00000000004008a0 <+303>: jmp 0x400896 <main+293>

End of assembler dump.

The main function sets up the stack, sets the standard output buffer to NULL (via setbuf@plt), saves the effective group ID, then calls setresgid@plt to set the real, effective, and saved group IDs to the effective group ID it just saved.

It then sets up some values on the stack. The strings are setup in memory on the stack. They are:

0x20656d6f636c6557 which is "Welcome to "

0x636520796d206f74 which is "my ec"

0x6576726573206f68 which is "ho serve"

0x2172 which is "r!" and then a null byte to terminate the string.

This string is "Welcome to my echo server!" when put together. The program then goes into a loop where it appears to convert each character of the string to a different case (lower to upper or upper to lower), storing the results in a new buffer on the stack.

Once the conversion is done, the converted string is printed to standard output using puts@plt, and then the do_stuff function is called.

Potential Vulnerabilities:

Buffer overflow: The most common vulnerability in such a code could be buffer overflow. However, without the details of the convert_case function or do_stuff, it's difficult to say exactly where an overflow might happen. The main place to look would be wherever user input is taken. If the length of the input isn't checked, an overflow can occur.

Predictable Stack Space Usage: The program allocates space on the stack in a predictable manner. If an attacker knows the size of the buffer used in the do_stuff function, they could manipulate their inputs to control the execution flow of the program.

Insecure Use of setresgid: Changing the real, effective, and saved group ID of a process can lead to privilege escalation if not done carefully.

Remember that these are only potential vulnerabilities, as without further information about the code (such as the convert_case and do_stuff functions, or how input is taken in), it's impossible to be certain about the exact vulnerabilities.

Preventing these vulnerabilities will involve careful handling of data, as well as proper configuration of privileges and resources. Here's a general idea on how you might do that:

Buffer Overflow: Ensure that you are checking the length of any user inputs and that it doesn't exceed the size of the buffer it is being copied into. For C, this might involve replacing dangerous functions like strcpy with safer versions like strncpy, which take the length of the buffer as a parameter. Additionally, consider using high-level constructs that manage memory safely, such as std::string in C++.

Predictable Stack Space Usage: Randomizing the location of the stack, a technique known as stack randomization, makes it harder for an attacker to predict where in memory their payload will end up, thus making the attack much harder. This is typically done by the operating system, not by individual programs. For Linux, you can enable Address Space Layout Randomization (ASLR) which does this.

Insecure Use of setresgid: Be very careful when changing the ID of a process. Only do it when necessary and immediately change it back when you're done. Ensure that the changes you're making don't grant additional privileges unintentionally.

Secure coding practices: Implement secure coding practices such as input validation, principle of least privilege, secure error handling, etc. These practices help to minimize the attack surface of your program and to mitigate the impact of any vulnerabilities that might still exist.

Regular security audits: Regularly audit your code for security issues. This can involve manual code review, using automated static analysis tools, or even hiring external security consultants.

c

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

void convert_case(int edi, long rsi);

void do_stuff();

int main(int argc, char **argv) {

setbuf(stdout, NULL);

gid_t gid = getegid();

setresgid(gid, gid, gid);

char str[] = "Welcome to my echo server!";

long len = 27; // The length of the string.

char buf[27]; // This buffer will store the case converted string.

for (long i = 0; i < len; i++) {

int ch = str[i];

ch = convert_case(ch, i);

buf[i] = ch;

}

puts(buf);

do_stuff();

return 0;

}

disas convert_case

Dump of assembler code for function convert_case:

0x0000000000400677 <+0>: push rbp

0x0000000000400678 <+1>: mov rbp,rsp

0x000000000040067b <+4>: mov eax,edi

0x000000000040067d <+6>: mov QWORD PTR [rbp-0x10],rsi

0x0000000000400681 <+10>: mov BYTE PTR [rbp-0x4],al

0x0000000000400684 <+13>: cmp BYTE PTR [rbp-0x4],0x60

0x0000000000400688 <+17>: jle 0x4006ab <convert_case+52>

0x000000000040068a <+19>: cmp BYTE PTR [rbp-0x4],0x7a

0x000000000040068e <+23>: jg 0x4006ab <convert_case+52>

0x0000000000400690 <+25>: mov rax,QWORD PTR [rbp-0x10]

0x0000000000400694 <+29>: and eax,0x1

0x0000000000400697 <+32>: test rax,rax

0x000000000040069a <+35>: je 0x4006a2 <convert_case+43>

0x000000000040069c <+37>: movzx eax,BYTE PTR [rbp-0x4]

0x00000000004006a0 <+41>: jmp 0x4006d6 <convert_case+95>

0x00000000004006a2 <+43>: movzx eax,BYTE PTR [rbp-0x4]

0x00000000004006a6 <+47>: sub eax,0x20

0x00000000004006a9 <+50>: jmp 0x4006d6 <convert_case+95>

0x00000000004006ab <+52>: cmp BYTE PTR [rbp-0x4],0x40

0x00000000004006af <+56>: jle 0x4006d2 <convert_case+91>

0x00000000004006b1 <+58>: cmp BYTE PTR [rbp-0x4],0x5a

0x00000000004006b5 <+62>: jg 0x4006d2 <convert_case+91>

0x00000000004006b7 <+64>: mov rax,QWORD PTR [rbp-0x10]

0x00000000004006bb <+68>: and eax,0x1

0x00000000004006be <+71>: test rax,rax

0x00000000004006c1 <+74>: je 0x4006cc <convert_case+85>

0x00000000004006c3 <+76>: movzx eax,BYTE PTR [rbp-0x4]

0x00000000004006c7 <+80>: add eax,0x20

0x00000000004006ca <+83>: jmp 0x4006d6 <convert_case+95>

0x00000000004006cc <+85>: movzx eax,BYTE PTR [rbp-0x4]

0x00000000004006d0 <+89>: jmp 0x4006d6 <convert_case+95>

0x00000000004006d2 <+91>: movzx eax,BYTE PTR [rbp-0x4]

0x00000000004006d6 <+95>: pop rbp

0x00000000004006d7 <+96>: ret

disas do_stuff

Dump of assembler code for function do_stuff:

0x00000000004006d8 <+0>: push rbp

0x00000000004006d9 <+1>: mov rbp,rsp

0x00000000004006dc <+4>: sub rsp,0x90

0x00000000004006e3 <+11>: mov QWORD PTR [rbp-0x10],0x0

0x00000000004006eb <+19>: lea rax,[rbp-0x80]

0x00000000004006ef <+23>: mov rsi,rax

0x00000000004006f2 <+26>: lea rdi,[rip+0x23b] # 0x400934

0x00000000004006f9 <+33>: mov eax,0x0

0x00000000004006fe <+38>: call 0x400580 <__isoc99_scanf@plt>

0x0000000000400703 <+43>: lea rax,[rbp-0x81]

0x000000000040070a <+50>: mov rsi,rax

0x000000000040070d <+53>: lea rdi,[rip+0x226] # 0x40093a

0x0000000000400714 <+60>: mov eax,0x0

0x0000000000400719 <+65>: call 0x400580 <__isoc99_scanf@plt>

0x000000000040071e <+70>: mov QWORD PTR [rbp-0x8],0x0

0x0000000000400726 <+78>: jmp 0x40075b <do_stuff+131>

0x0000000000400728 <+80>: lea rdx,[rbp-0x80]

0x000000000040072c <+84>: mov rax,QWORD PTR [rbp-0x8]

0x0000000000400730 <+88>: add rax,rdx

0x0000000000400733 <+91>: movzx eax,BYTE PTR [rax]

0x0000000000400736 <+94>: movsx eax,al

0x0000000000400739 <+97>: mov rdx,QWORD PTR [rbp-0x8]

0x000000000040073d <+101>: mov rsi,rdx

0x0000000000400740 <+104>: mov edi,eax

0x0000000000400742 <+106>: call 0x400677 <convert_case>

0x0000000000400747 <+111>: mov ecx,eax

0x0000000000400749 <+113>: lea rdx,[rbp-0x80]

0x000000000040074d <+117>: mov rax,QWORD PTR [rbp-0x8]

0x0000000000400751 <+121>: add rax,rdx

0x0000000000400754 <+124>: mov BYTE PTR [rax],cl

0x0000000000400756 <+126>: add QWORD PTR [rbp-0x8],0x1

0x000000000040075b <+131>: cmp QWORD PTR [rbp-0x8],0x63

0x0000000000400760 <+136>: jbe 0x400728 <do_stuff+80>

0x0000000000400762 <+138>: lea rax,[rbp-0x80]

0x0000000000400766 <+142>: mov rdi,rax

0x0000000000400769 <+145>: call 0x400540 <puts@plt>

0x000000000040076e <+150>: nop

0x000000000040076f <+151>: leave

0x0000000000400770 <+152>: ret

End of assembler dump.

c

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

// Convert case function

int convert_case(int ch, long idx) {

if (ch > 0x60 && ch <= 0x7a) { // Check if character is lowercase

if (idx & 0x1) { // Check if index is odd

return ch;

} else {

return ch - 0x20; // Convert to uppercase

}

} else if (ch > 0x40 && ch <= 0x5a) { // Check if character is uppercase

if (idx & 0x1) { // Check if index is odd

return ch + 0x20; // Convert to lowercase

} else {

return ch;

}

} else {

return ch;

}

}

// The do_stuff function, which seems to take input from the user and modify it

void do_stuff() {

char input[128];

printf("Enter your input: ");

scanf("%127s", input); // Prevent buffer overflow by limiting input length

for (int i = 0; i < 100 && input[i] != '\0'; i++) {

input[i] = convert_case(input[i], i);

}

puts(input);

}

// Main function

int main(int argc, char **argv) {

setbuf(stdout, NULL);

gid_t gid = getegid();

setresgid(gid, gid, gid);

char str[] = "Welcome to my echo server!";

long len = sizeof(str) / sizeof(str[0]) - 1; // Calculate string length

char buf[len + 1]; // This buffer will store the case converted string.

for (long i = 0; i < len; i++) {

int ch = str[i];

buf[i] = convert_case(ch, i);

}

buf[len] = '\0'; // Null terminate the string

puts(buf);

do_stuff();

return 0;

}

In do_stuff(), the user is prompted to input a string. The string is then modified using the convert_case function before being output with puts(). This implementation of do_stuff is based on the assembly code provided and attempts to replicate its functionality.

Remember to always compile and test your code in a controlled environment before using it in production.

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

// Convert case function

int convert_case(int ch, long idx) {

if (ch > 0x60 && ch <= 0x7a) { // Check if character is lowercase

if (idx & 0x1) { // Check if index is odd

return ch;

} else {

return ch - 0x20; // Convert to uppercase

}

} else if (ch > 0x40 && ch <= 0x5a) { // Check if character is uppercase

if (idx & 0x1) { // Check if index is odd

return ch + 0x20; // Convert to lowercase

} else {

return ch;

}

} else {

return ch;

}

}

// The do_stuff function, which seems to take input from the user and modify it

void do_stuff() {

char input[128];

printf("Enter your input: ");

scanf("%127s", input); // Prevent buffer overflow by limiting input length

for (int i = 0; i < 100 && input[i] != '\0'; i++) {

input[i] = convert_case(input[i], i);

}

puts(input);

}

// Main function

int main(int argc, char **argv) {

setbuf(stdout, NULL);

gid_t gid = getegid();

setresgid(gid, gid, gid);

char str[] = "Welcome to my echo server!";

long len = sizeof(str) / sizeof(str[0]) - 1; // Calculate string length

char buf[len + 1]; // This buffer will store the case converted string.

for (long i = 0; i < len; i++) {

int ch = str[i];

buf[i] = convert_case(ch, i);

}

buf[len] = '\0'; // Null terminate the string

puts(buf);

do_stuff();

return 0;

}

This C code is a simple program that does two main things:

It echoes a predefined string ("Welcome to my echo server!") with some character conversions applied.

It then allows the user to enter a string which it also modifies using the same character conversions before printing it out.

Below are more specific details:

convert_case(int ch, long idx): This function takes a character and its index in a string as inputs. It checks if the character is a lowercase letter (ascii value between 0x61 and 0x7a inclusive) or an uppercase letter (ascii value between 0x41 and 0x5a inclusive). If the character is a letter and its index is odd, it leaves the character as is. If the character is a letter and its index is even, it changes the case of the character. If the character is not a letter, it leaves it as is.

do_stuff(): This function first gets a string input of up to 127 characters from the user. It then converts the case of the letters in this input string using the convert_case function and prints the result.

main(int argc, char **argv): The main function of this program. It first disables output buffering for stdout and sets the real, effective, and saved group IDs of the calling process to the effective group ID of the process. This can be a security measure in setuid programs. It then creates a string str with the message "Welcome to my echo server!" and applies the convert_case function to each character in this string. It then prints the converted string and calls do_stuff.

Here's a quick note about the setbuf(stdout, NULL); and setresgid(gid, gid, gid); lines in the main function:

setbuf(stdout, NULL); is used to disable buffering for stdout. Normally, stdout is line-buffered or fully-buffered depending on whether it's connected to a terminal. By disabling buffering, the program ensures that output to stdout is written immediately.

setresgid(gid, gid, gid); is often used in setuid programs for privilege separation. It sets the real GID, effective GID, and saved set-group-ID of the calling process. This is generally done to drop privileges and minimize the potential damage if the program is exploited. Here it's not accomplishing much because it's setting all IDs to the effective group ID of the process.

 

 

애초에 설계, 엔지니어링, 디버깅 할 때부터 보안 취약점이 없도록 AI가 직접 코드를 짜고 다시 수정하고 다시 짜는데 도대체 어떻게 드림핵같이 장난만 뽀작 거려서 뭘 하겠다는 걸까용 ~?

이제 새로운 AI agent와 현대 바이너리 보호기법 등을 합치면 드림핵같이 뽀작뽀작 거려봤자 아무 의미가 없어질 겁니당 ~

중요한 건 그런게 아니에요 뽀너블 1000만 번 1억 번 해보세용 이제 다 그런 건 의미가 없으니 ~~

진짜 해킹&보안은 그런 게 아니에용~

728x90

'행복한 프로그래밍' 카테고리의 다른 글

문자열 초기화   (0) 2018.06.01
문자열 입력   (0) 2018.06.01
break continue  (0) 2018.06.01
break사용하기   (0) 2018.06.01
거듭제곱   (0) 2018.06.01