Vagrant를 이용한 커널 디버깅

[0x00] Overview

커널 디버깅을 진행하기 위한 선행 작업으로 가상머신 설정에 많은 시간을 소모합니다. 이러한 설정을 좀 더 가볍게 할 수 있도록 Vagrant를 이용할 수 있습니다. 쉽게 생각하면 도커와 비슷한 개념으로 생각할 수 있습니다. 해당 글에서는 이러한 Vagrant를 이용하여 커널 디버깅을 좀 더 쉽게 설정하고 자동화할 수 있는 방법에 대해 설명합니다.

이 글에서는 VagrantHypervisor가 설치되었다는 가정하에 진행합니다. 이곳을 클릭 하여 다운로드 받을 수 있습니다.

Vagrant가 지원하는 하이퍼바이저는 아래와 같습니다.

  • VirtualBox
  • VMWare
  • Hyper-V

제공되는 내용에서는 VirtualBox를 이용합니다. 다만 공식 가이드에서는 안정성과 속도의 측면에서 VMWare를 추천한다고 되어있습니다.

[0x01] Create Box Image

Vagrant에는 최소 디스크 크기의 이미지인 box 라는 개념을 가지고 있습니다. 부팅하는데 최소한의 소프트웨어만 존재하는 상태를 의미합니다. 이러한 박스는 쉘 스크립트를 이용하여 가상 머신 템플릿을 구성할 수 있습니다. Vagrant Cloud 에는 다른 사용자가 공개적으로 사용 가능한 박스 이미지들이 업로드되어 있습니다. 해당 부분은 아래의 활용 부분에서 더 다루도록 하겠습니다.

먼저 게스트 OS를 설치 후 계정명과 패스워드는 "vagrant"로 설정해야 합니다. 설치 후 Vagrant Documentation 에 따르면 다음과 같은 작업이 필요합니다.

  • Install the guest tools for your hypervisor.
  • Ensure the virtual network adapter is configured as a private network.
  • Completely disable UAC.
  • Disable complex passwords.
  • Disable Shutdown Tracker.

그리고 Vagrant가 게스트 OS 내에서 스크립트를 실행할 수 있도록 winrm을 사용하여 원격 관리를 활성화해야 합니다. 관리자 권한으로 명령 프롬프트를 실행하고 다음과 같이 실행하십시오.

winrm quickconfig -q
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="512"}
winrm set winrm/config @{MaxTimeoutms="1800000"}
winrm set winrm/config/service @{AllowUnencrypted="true"}
winrm set winrm/config/service/auth @{Basic="true"}
sc config WinRM start= auto

이제 위에서 말한 박스 이미지로 만들 수 있는 하나의 게스트 OS가 완성되었습니다. 아무런 작업을 하지말고 게스트 OS를 종료하십시오.

다음은 호스트 OS에서의 작업입니다. 가상 머신 파일이 있는 디렉토리에서 명령 프롬프트를 열고 아래와 같이 vagrant 명령을 실행합니다. 가상 머신을 박스 이미지로 만드는 과정입니다.

vagrant package --base <VM name> --output <Box name>
PS D:\06_Vagrant_Box\Windows10_1909_18363_418(x64)> vagrant package --base "Windows10_1909_18363_418(x64)" --output Windows10_1909.box                                                                                                          ==> Windows10_1909_18363_418(x64): Exporting VM...
==> Windows10_1909_18363_418(x64): Compressing package to: D:/06_Vagrant_Box/Windows10_1909_18363_418(x64)/Windows10_1909.box

확인해보면 원래 VM 크기의 절반정도 크기로 만들어진 box 파일을 확인할 수 있습니다. 다음 Vagrant의 박스에 추가해야 합니다.

vagrant box add <prefix/box> <box image file>
PS D:\06_Vagrant_Box\Windows10_1909_18363_418(x64)> vagrant box add shh0ya/win10k Windows10_1909.box
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'shh0ya/win10k' (v0) for provider:
    box: Unpacking necessary files from: file://D:/06_Vagrant_Box/Windows10_1909_18363_418(x64)/Windows10_1909.box
    box:
==> box: Successfully added box 'shh0ya/win10k' (v0) for 'virtualbox'!

PS D:\06_Vagrant_Box\Windows10_1909_18363_418(x64)> vagrant box list
shh0ya/win10k (virtualbox, 0)
PS D:\06_Vagrant_Box\Windows10_1909_18363_418(x64)>

위와 같이 박스가 생성된 것을 확인할 수 있습니다.

[0x02] Vagrant Up

이제 박스가 준비되었습니다. 작성자는 다음과 같은 디렉토리 구조에서 진행하였습니다.

PS D:\> tree D:\06_Vagrant_Box /F                                                                     
D:\06_VAGRANT_BOX
├─Box_Win10_1909_18363_418(x64)
└─Windows10_1909_18363_418(x64)
    │  Windows10_1909.box
    │  Windows10_1909_18363_418(x64).vbox
    │  Windows10_1909_18363_418(x64).vbox-prev
    │  Windows10_1909_18363_418(x64).vdi
    │
    └─Logs
            VBox.log
            VBox.log.1
            VBox.log.2
            VBoxHardening.log

접두어로 Box가 존재하는 디렉터리에는 실제 Vagrant에서 박스를 실행할 때 필요한 설정 파일들과 배치파일들을 작성할 것입니다. 위에서 가상 머신을 박스 이미지로 추출하고 Vagrant에 등록되었으므로 원하는 경로에 설정 파일을 등록하고 실행할 수 있습니다.

원하는 디렉토리에 Vagrantfile 파일을 생성하십시오. 이는 박스를 실행할 때 여러가지 작업을 자동화할 수 있습니다.

# File name : Vagrantfile

Vagrant.configure("2") do |config|
  config.vm.guest = :windows
  config.vm.communicator = "winrm"

  config.winrm.password = "vagrant"
  config.winrm.username = "vagrant"	
  
  config.vm.define "win10" do |win10|
    win10.vm.box = "shh0ya/win10k"
    
    win10.vm.provision "shell", path: "guest/kdbg.bat"
    win10.vm.network :forwarded_port, guest: 49152, host: 49152		
  end
end

각 설정에 대해 설명하겠습니다.

  • vm.guest = :windows ; 기반의 게스트 OS임을 Vagrant에 명시합니다.
  • vm.communicator = “winrm” ; 게스트OS를 winrm을 통해 관리합니다.
  • winrm.password = “vagrant” ; 초기 설정한 계정명과 패스워드입니다.
  • winrm.username = “vagrant”
  • vm.box = “shh0ya/win10k” ; Vagrant에 추가되어 있는 박스 이름입니다.
  • vm.provision “shell”, path: “guest/kdbg.bat” ; 박스가 실행되고 실행 될 스크립트 파일입니다.
  • vm.network :forward_port, guest: 49152, host: 49152 ; 호스트에게 커널 디버깅 포트를 노출합니다.

프로비저닝 옵션에 명시한 것과 같이 해당 디렉토리 내 guest 디렉토리 안에 배치파일을 생성할 것입니다. 해당 배치파일에는 디버그 모드 활성화를 하는 내용으로 작성됩니다.

# File name : kdbg.bat

bcdedit /debug on
bcdedit /dbgsettings net hostip:192.168.56.1 port:49152 key:1.1.1.1
shutdown /r /t 0

이제 모든 준비가 되었습니다. 직접 만든 박스 이미지를 실행하고 커널 디버깅을 할 수 있습니다. 작성자의 디렉토리 구조입니다.

D:\06_VAGRANT_BOX
├─Box_Win10_1909_18363_418(x64)
│  │  Vagrantfile
│  │
│  └─guest
│          kdbg.bat
│
└─Windows10_1909_18363_418(x64)
    │  Windows10_1909.box
    │  Windows10_1909_18363_418(x64).vbox
    │  Windows10_1909_18363_418(x64).vbox-prev
    │  Windows10_1909_18363_418(x64).vdi
    │
    └─Logs
            VBox.log
            VBox.log.1
            VBox.log.2
            VBoxHardening.log

현재 설정은 네트워크 디버깅입니다. 다만 좀 더 깊은 분석을 원한다면 직렬포트를 이용하여 디버깅 하길 바랍니다. 자동으로 windbg를 실행하고 디버깅 연결까지 아래와 같은 스크립트로 가능합니다.

start vagrant up
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -k net:port=49152,key=1.1.1.1

수 초내에 가능할 것 같았지만 조금은 더 걸리는 것 같습니다. 그래도 원클릭으로 디버깅이 가능합니다

[-] Using Serial port

직렬포트를 이용하기 위해서는 기존에 가상머신 템플릿에 직렬포트 설정을 해줘야 합니다. 그리고 박스 이미지를 만들면 같은 설정이 됩니다.

이에 따른 프로비저닝 스크립트와 자동실행 스크립트는 아래와 같습니다.

# File name : kdbg.bat
bcdedit /debug on
bcdedit /dbgsettings serial debugport:1 baudrate:115200
shutdown /r /t 0
# File name : VagrantStart.bat
start vagrant up
timeout 15
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe" -k com:port=\\.\pipe\debugmode,baud=115200,pipe,reconnect,resets=0

간혹 디버거가 붙지 않는 현상이 있어 위와 같이 타임아웃을 정해주는 것으로 해결하였습니다. 위의 스크립트에서는 파이프 이름과 디버그 포트만 맞게 설정해주면 됩니다.(부팅 도중 Vagrant에서 간섭하는 부분과 충돌이 있는 듯 합니다.)

[0x03] Conclusion

여기까지 Vagrant 설치 및 활용에 관한 내용이었습니다. 사실 박스 이미지를 구축하는 내용이 대부분이지만, 그 외 Vagrant Cloud에서 찾을 수 있기 때문입니다.

도커와 같이 사용자들이 제작하여 업로드합니다. 활용에 맞는 이미지를 골라 vagrant init <box name> 명령을 통해 간단히 내려받고 실행할 수 있습니다.

[0x04] Reference

  1. SecretClub