Bài tập 1: Python Cơ bản
Mục tiêu:
- Tạo các kịch bản Python cơ bản và khám phá các tính năng và thành phần của Python
Thời gian thực hành: 20 phút
- Trong bài thực hành này, bạn sẽ xem xét framework Python và tạo các kịch bản Python đơn giản.
- Theo mặc định, máy Python-Machine được chọn, nhập password trong trường Mật khẩu và nhấn Enter. (Hình ảnh màn hình đăng nhập Ubuntu)
- Mở terminal và gõ python –version và nhấn Enter. Sau đó, gõ python3 –version và nhấn Enter. (Hình ảnh màn hình terminal hiển thị kết quả của cả hai lệnh)
- Bạn có hai phiên bản Python khác nhau, điều này là phổ biến, vì một số mã hoạt động với một phiên bản và một số mã hoạt động với phiên bản khác. Tốt nhất nên giữ cả hai phiên bản cho đến khi bạn quen với việc kiểm tra các kịch bản cụ thể. Sự khác biệt không đáng kể. (Hình ảnh màn hình terminal)
- Tạo một kịch bản điều kiện đơn giản. Nhấp vào biểu tượng Leafpad để khởi chạy trình soạn thảo văn bản. Nhập mã sau như được hiển thị trong ảnh chụp màn hình và lưu dưới dạng myfirst.py trên Desktop: (Hình ảnh mã Python trong Leafpad)
a = 4
b = 5
if a > b:
print("A is Greater!")
elif a < b:
print("B is Greater!")
else:
print("A is either Greater or Equal!")
print("End!")
Use code with caution.Python
- Trong terminal, gõ cd Desktop và nhấn Enter để thay đổi vị trí thư mục. Gõ python myfirst.py và nhấn Enter. Đây là một đoạn mã đơn giản cho thấy câu lệnh if, hoạt động tương tự trong nhiều ngôn ngữ. (Hình ảnh màn hình terminal hiển thị kết quả của tập lệnh)
- Tiếp theo, hãy quan sát vòng lặp “while”. Mở một trình soạn thảo Leafpad mới và nhập mã như được hiển thị trong ảnh chụp màn hình và lưu dưới dạng while.py trên Desktop. (Hình ảnh mã Python trong Leafpad)
print("**** While Basics ****")
a = 0
while a < 5: # Without braces ; Statement is "a += 1"
a += 1
print("Statement "+str(a))
print("**** While with Lists ****")
l = [1,2,3]
a = 0
while a < len(l): # Without braces ; Statement is "a += 1"
print(l[a])
a += 1
print("**** While Loop with Type Casting and Found Control ****")
i=1
l = [1,2,3,"Apple", 4.0, "Found", 5]
while i < len(l) and l[i] != "Found":
if (type(l[i]) == type(1)):
print("Found Integer :"+str(l[i]))
elif (type(l[i]) == type("Hello")):
print("Found String : "+str(l[i]))
else:
print("Found : "+str(l[i])) # Now lets iterate.....
i+=1
print("**** Inner list Lets iterate..... ****")
i = 1
l = [[1,2,3],[4,5,6],[7,8,9]]
while i < len(l):
j = 0
while j < len(l[i]):
print("Neither Integer nor string :"+str(l[i][j])+" and Type is : "+str(type(l[i][j])))
j+=1
i+=1
Use code with caution.Python
- Gõ python while.py và nhấn Enter. (Hình ảnh màn hình terminal hiển thị kết quả của tập lệnh)
- Tiếp tục và chuyển sang các tập lệnh thực tế để kiểm tra. Bắt đầu và làm theo cách của bạn. Nếu bạn mới bắt đầu với IP và các mạng và vòng lặp, thì bạn cần khám phá thêm và thực hành. Bây giờ hãy chuyển sang phần socket.
- Vì bạn đang ở trên máy tấn công và bạn chủ yếu quan tâm đến việc tạo dữ liệu trên mạng giống như trình duyệt hoặc ứng dụng của bạn sẽ gửi đến nhà cung cấp dịch vụ internet hoặc máy đích của bạn, bạn sẽ bắt đầu với một SOCKS đơn giản và xây dựng từ đó. Khi bạn tạo UDP, bạn sẽ hiểu TCP (Giao thức kiểm soát truyền) cũng như dữ liệu khi bạn tạo UDP (Giao thức dữ liệu người dùng). Để tạo socket, hãy thiết kế mã dưới đây:
- s = socket.socket() — Đây là API cho socket và socket families. Có hai tùy chọn socket families: AF_INET (IPV4) và socket families khác.
- Để tạo socket, hãy chỉ định AF_INET, SOCK_STREAM.
- AF_INET là tùy chọn cho địa chỉ local IPv4. SOCK_STREAM là tùy chọn cho TCP, và nếu là RAW, bạn cũng có socket families AF_INET, SOCK_RAW cho socket kiểu User Datagram Protocol (UDP) hoặc SOCK_RAW cho raw socket.
- Khi bạn đã tạo socket, hãy sử dụng các hàm trong socket family để tạo kết nối.
- Tạo một banner grab đơn giản bằng Python. Trong terminal, gõ python3 và nhấn Enter. (Hình ảnh màn hình terminal Python3)
- Trong terminal Python, gõ mã sau như được hiển thị trong ảnh chụp màn hình: (Hình ảnh mã Python trong terminal)
import socket
bangrab = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bangrab.connect(('192.168.77.200', 60000))
bangrab.recv(4096)
bangrab.close
Use code with caution.Python
- Secure Shell (SSH) server được ràng buộc với cổng 60000 trên máy ví dụ. Chúng ta có thể thêm قابلیت để tương tác với một web server. Tuy nhiên, để làm điều này, bạn cần phải mở rộng mã hiện có. Một ví dụ về cách bạn có thể làm điều này được hiển thị trong chuỗi mã sau đây:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.connect((“http://”, lhost, “:”, lport))
- page = 1
- while 1:
- data = s.recv(1024)
- if data == “”:
- break
- page += data
- print page
- 192.168.77.200 là địa chỉ IP của máy Web-Python.
- Socket send method nhận một đối số: chuỗi mà bạn muốn gửi. Trong trường hợp này, bạn đang gửi một yêu cầu đến máy OWASP. Đầu tiên, hãy khởi tạo biến page bằng một chuỗi rỗng để đảm bảo bạn không chọn bất kỳ rác nào có thể còn sót lại trong bộ nhớ. Khi bạn đã có chuỗi rỗng, hãy tạo mã cho một vòng lặp để liên tục nhận dữ liệu lên đến lượng dữ liệu bạn nhận được, là 1024 byte trong ví dụ này. Vì bạn đang đặt giá trị của hàm recv thành “”, nó sẽ tiếp tục cho đến khi không còn nội dung nào để đọc, cho biết socket đã đóng. Thêm mã để đóng socket và in dữ liệu bằng cách sử dụng các lệnh bên dưới:
- s.close()
- print page
- Mở một trình soạn thảo Leafpad mới và nhập mã như được hiển thị trong ảnh chụp màn hình và lưu dưới dạng web-conn.py trên Desktop. (Hình ảnh mã Python trong Leafpad)
#!/usr/bin/python
import socket
lhost="192.168.77.157"
lport=80
#create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect to the host/target
s.connect((lhost,lport))
#send some data
page = ""
while 1: #while data is still coming back, append to our page variable
data = s.recv(1024)
if data == "":
break
page += data
#Close our socket and print the results
s.close()
print page
Use code with caution.Python
- Trong terminal, gõ cd Desktop và nhấn Enter để thay đổi vị trí thư mục. Gõ python web-conn.py và nhấn Enter. (Hình ảnh màn hình terminal hiển thị kết quả của tập lệnh)
- Tuy nhiên, có một nhược điểm của ví dụ trên là nó dành cho Python 2 và cũng chỉ dành cho IPv4. Điều này là không thể tránh khỏi khi làm việc với các phiên bản Python khác nhau. Giải pháp phổ biến là sửa đổi mã để hoạt động với cả hai phiên bản. Nếu bạn nhận được lỗi socket.gaierror: [Errno -2] Name or service not known khi nhập http://www.eccouncil.org:80:80 thì bạn cần phải chỉ định SOCK_STREAM cho socket.
- Liên quan đến cổng, hãy cân nhắc family bạn đang sử dụng để xác định. Điều này sẽ loại bỏ các cổng nằm ngoài family bạn đang sử dụng (ví dụ: getaddrinfo) và điều này sẽ cho phép nó hoạt động với UDP, TCP, hoặc IP. Hàm nmap module family cho phép một mảng địa chỉ IP có thể để làm việc.
- Khởi động một terminal mới và nhập các lệnh sau. Sử dụng Python 3 để có thể hoạt động:
- python3
- import nmap
- nm = nmap.PortScanner()
- nm.scan(‘127.0.0.1’, ‘53,443,3306,60000’) (Hình ảnh màn hình terminal hiển thị kết quả)
- Mặc dù bước này hoạt động, nhưng nó không phải là định dạng tốt nhất. Điều quan trọng là bạn phải thực hiện các cải tiến. Kiểm tra xem đầu ra có phải là do bạn đã yêu cầu nhiều hơn một cổng hay không. Nhập:
- nm.scan(‘127.0.0.1′, ’22’) (Hình ảnh màn hình terminal hiển thị kết quả)
- Đầu ra vẫn chưa được định dạng tốt. Bạn có thể loại bỏ thực tế là nó bị gây ra bởi số lượng cổng. Tiếp theo, hãy khám phá các phương pháp tốt hơn.
- Trước khi làm như vậy, hãy thay đổi quét và thu thập thêm máy. Nhập mã sau:
- nm.scan(‘192.168.177.0/24′, ’22-60000’) (Hình ảnh màn hình terminal hiển thị kết quả)
- Bây giờ bạn đang chuyển các đối số vào công cụ nm.all_hosts(), tiếp theo là một lần quét.
- Khi quét hoàn tất, hãy nhập nm.all_hosts(). Kết quả được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal hiển thị kết quả)
- Module này chứa nhiều tùy chọn để hỗ trợ chúng ta hiểu rõ hơn về đầu ra thô. Lệnh đầu tiên là nm.command_line(). (Hình ảnh màn hình terminal hiển thị kết quả)
- Vì bạn đã tạo output nmap, kiểu dáng chuẩn cho phép bạn xem đầu ra ở dạng dễ đọc hơn. Vì bạn đã biết module, hãy sử dụng hàm được thêm vào và xuất ra dưới dạng XML. Nhập mã sau:
- nm.scan(arguments=’-n -A -p 22 -oX nse’)
Bài tập 2: Mạng cơ bản và Python
Mục tiêu:
- Tạo các kịch bản Python đơn giản về mạng
Thời gian thực hành: 20 phút
- Trong bài thực hành này, bạn sẽ tạo một số kịch bản mạng Python đơn giản; cái đầu tiên là một client TCP.
- Theo mặc định, máy Python-Machine được chọn, hãy nhập password vào trường Mật khẩu và nhấn Enter. Nếu bạn đã đăng nhập, hãy bỏ qua bước 3. (Hình ảnh màn hình đăng nhập Ubuntu)
- Nhập mã dưới đây vào trình soạn thảo bạn chọn và lưu dưới dạng TCPclient.py trên Desktop. 192.168.177.157 là địa chỉ IP của máy WinPy-Python. (Hình ảnh mã Python trong Leafpad)
import socket
target_host = "192.168.77.157"
target_port = 2090
#create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the client
client.connect((target_host,target_port))
#send some data
client.send("GET / HTTP/1.1\r\nHost: 192.168.177.157\r\n\r\n")
#receive some data
response = client.recv(4096)
print response
Use code with caution.Python
- Khởi chạy terminal và gõ cd Desktop và nhấn Enter. Chạy python TCPclient.py và nhấn Enter. Lưu ý việc tạo socket. Hơn nữa, bạn có socket TCP, kết nối với nó, gửi yêu cầu GET, lưu phản hồi và in ra như được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal hiển thị kết quả của tập lệnh)
- Lưu ý rằng mã này không được thiết lập để kiểm tra lỗi, nhưng nó sẽ phục vụ mục đích. Khi bạn tạo kịch bản trong quá trình thử nghiệm, hiếm khi thêm kiểm tra lỗi bổ sung, trừ khi đó là kiểm tra tùy chỉnh. Vì bạn đang sử dụng UDP (User Datagram Protocol), hãy thay đổi kiểu socket.
- Đối với UDP, hãy sử dụng SOCK_DGRAM thay vì SOCK_STREAM. UDP không có kết nối.
- Bây giờ bạn đã sẵn sàng để tạo server. Server phức tạp hơn một chút. Bắt đầu với socket giao tiếp, bạn tạo socket, sau đó gán nó với một bộ ghép địa chỉ và cổng, và lắng nghe các kết nối. Sau khi hoàn thành bước này, hãy đặt trong một vòng lặp và chu kỳ và chờ kết nối.
- Nhập mã được hiển thị bên dưới. Lưu ý rằng mã này dành cho Python 2.7 và không phải Python 3. (Hình ảnh mã Python trong trình soạn thảo văn bản)
bind_ip = "0.0.0.0"
bind_port = 9999
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip,bind_port))
server.listen(5)
print "[*] Listening on %s:%d" % (bind_ip,bind_port)
#this is our client-handling thread
def handle_client(client_socket):
#print out what the client sends
request = client_socket.recv(1024)
print "[*] Received: %s" % request
#send back a packet
client_socket.send("ACK!")
client_socket.close()
while True:
client,addr = server.accept()
print "[*] Accepted connection from: %s:%d" % (addr[0],addr[1])
#spin up our client thread to handle incoming data
client_handler = threading.Thread(target=handle_client,args=(client,))
client_handler.start()
Use code with caution.Python
- Đầu tiên, chuyển địa chỉ IP và cổng bạn muốn server nghe. Đây chỉ là một lần. Tiếp theo, máy chủ sẽ bắt đầu nghe với tối đa năm kết nối đang hoạt động. Bạn có thể thực hiện không giới hạn số lượng kết nối. Điều này chỉ là để làm cho mã đơn giản hơn.
- Đặt đoạn mã này vào vòng lặp chính của nó, nơi nó chờ một kết nối đến. Sau khi có kết nối, nó sẽ chuyển một socket mới đến một thread mới để xử lý client. Điều này được gọi là lập trình “hướng sự kiện”, trong đó vòng lặp chạy liên tục, chờ các sự kiện để hành động.
- Bạn có thể sửa đổi mã client để kết nối với loopback, sau đó gửi dữ liệu đến server bằng cách sử dụng các thay đổi được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong trình soạn thảo văn bản)
target_host = "127.0.0.1"
#replace the ip address with the machine you want to connect to
target_port = 2090
#circle a number above
#create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the client
client.connect((target_host,target_port))
#and send some data
client.send("Arbitrary")
Use code with caution.Python
- Chạy client. Server sẽ nhận được chuỗi bạn đã gửi. (Hình ảnh màn hình terminal)
- Một lần nữa, đây chỉ là một server cơ bản mà bạn sử dụng để tập trung vào các khái niệm. Điều này được chấp nhận từ quan điểm của các yêu cầu kiểm tra thâm nhập của bạn. Có thể có các cải tiến sau:
- Bạn có thể muốn tạm dừng input từ client.
- Bạn có thể muốn xử lý nhiều kết nối từ client cùng một lúc.
- Để làm điều này, hãy thêm một đối số vào câu lệnh server.listen. Ví dụ, nếu bạn muốn lắng nghe X lượng kết nối — trong trường hợp này là 10 — hãy thêm câu lệnh sau:
- server.listen(10)
- Câu lệnh này thêm một đối số vào hàm để thiết lập số kết nối cần xử lý. Sau đó, đặt một đối số mà bạn sẽ sử dụng để lưu dữ liệu client vào một biến.
- Thành phần tiếp theo mà bạn cần là khả năng thực hiện trích xuất. Trong thư viện, bạn có module select cung cấp khả năng này. Sử dụng câu lệnh sau:
- select.select(r,w,e,1)
- Module này nhận các đối số sau:
- Một danh sách socket để kiểm tra xem có thể đọc hay không.
- Một danh sách socket để kiểm tra xem có thể ghi hay không.
- Một danh sách socket để kiểm tra lỗi.
- Về cơ bản, phương thức này trả về ba danh sách.
- Khi bạn đã đọc nó, hãy xem xét nó bằng cách lặp qua mảng:
- for sock in r:
- if sock is addr:
- print “New connection”
- addr = s.accept()
- Ở đây, bạn tìm kiếm socket phù hợp trong mảng. Nếu bạn tìm thấy socket cần thiết, hãy chấp nhận kết nối. Sau đó, chấp nhận thông báo kết nối và nối thông báo đó thành một chuỗi được gọi là lệnh để thực thi.
- Tiếp tục mã và thêm câu lệnh else phản ánh dữ liệu:
- else:
- sock.recv(1024)
- command += data
- Nếu command không phải là socket giống như client ban đầu, hãy đóng socket đó. Bạn đã sẵn sàng để xử lý thông tin. Đọc thông tin đó vào một chuỗi có tên là lệnh. Nếu không có dữ liệu nào đang chờ xử lý trên socket, thì hãy tắt nó và xóa nó. Khi bạn đã sẵn sàng, hãy thực thi lệnh đã thu thập bằng cách sử dụng các thư viện của Python. Thực thi lệnh rất đơn giản: bạn loại bỏ bất kỳ khoảng trắng nào ở cuối, sau đó tách chuỗi. Cuối cùng, bạn thực thi chuỗi trong shell.
- Việc xử lý một server có thể phức tạp hơn nhiều. Tester thâm nhập thường thực hiện xử lý này bằng cách chặn raw socket.
- Tiếp theo, khám phá các client raw socket.
- Khám phá các phương thức để sử dụng Python và các thư viện của nó để trích xuất dữ liệu gói ở mức thấp.
- Cả Windows và Linux đều có khả năng trích xuất chi tiết ở mức mạng. Windows sẽ cung cấp cho bạn khả năng trích xuất thông tin chi tiết về tiêu đề IP bằng cách sử dụng raw socket. Vì vậy, bạn có thể truy xuất thông tin này.
- Khi bạn viết một đoạn mã để lấy mã, hãy xác định hệ điều hành mà mã đó sẽ được chạy. Các phiên bản gần đây nhất của Windows NT của Microsoft vẫn được duy trì và có cùng cấu trúc kernel cho đến Windows 10. Vì vậy, kiến trúc mạng, ring 3, ring 2, ring 1, và ring 0 đều giống nhau. Sự cố nằm ở việc tiếp cận kernel và luôn như vậy. Trong chế độ user mode, bạn không thể trích xuất raw packets. Ví dụ mã ở dưới sẽ chỉ có thể lấy các packets ở user mode của hệ điều hành. Tóm tắt là như sau:
- Ring 3 — User mode
- Ring 2 — Không được sử dụng
- Ring 1 — Không được sử dụng
- Ring 0 — Kernel
- Sự cố với phương pháp này là các tiến trình ở chế độ user mode sẽ không thể lấy các packets ở chế độ kernel.
- Một ví dụ về sniffer đơn giản này đọc một packet được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong trình soạn thảo văn bản)
#topics = socket, struct
import socket
import os
import struct
# host to listen on
host = "192.168.1.101"
#create a raw socket and bind it to the public interface
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
#we want the ip headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# if we're using windows, we need to send an IOCTL
#to setup promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
#read in a single packet
print sniffer.recvfrom(65565)
# if we're using windows, turn off promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
Use code with caution.Python
- Chúng ta bắt đầu bằng cách tạo đối tượng socket với các tham số cần thiết để lấy các packet trên giao diện mạng. Sự khác biệt giữa Windows và Linux là tham số được chuyển đến socket. Tham số này tham chiếu đến giao thức IP. Windows sử dụng tham số IP, trong khi Linux sử dụng tham số được chuyển vào — ví dụ như Internet Control Message Protocol (ICMP).
- Bạn đang sử dụng bước setsockopt để đưa máy tính của bạn vào chế độ promiscous. Bạn đang cố gắng chạy mã mà không có quyền thích hợp, như được hiển thị trong ví dụ.
- Thực hiện hành động sniffing. Trong ví dụ này, bạn chỉ sniffing một packet. Sau đó, tắt chế độ promiscous. (Hình ảnh màn hình terminal)
- Đầu ra ở dạng thô và được tạo từ máy mà bạn đã gửi packet. Bạn thấy máy gửi packet vì nội dung của packet sử dụng các ký tự viết thường và dấu câu. Ngược lại, tiêu đề được tạo bởi hệ thống Windows bằng cách sử dụng các ký tự viết hoa và một thành phần mặc định. Điều này là tầm thường đối với chúng ta để sửa đổi bằng cách sử dụng các tùy chọn piping cũng như bằng cách giải mã nó.
- Như hiện tại, sniffer sẽ nhận tất cả các packet trong bất kỳ hình thức nào, như TCP, UDP, hoặc ICMP. Thông tin được chuyển đến tiêu đề sẽ hoạt động cùng với các giao thức cấp cao hơn, nhưng khó có thể trích xuất và sử dụng thông tin như kiểu giao thức trong packet, cũng như địa chỉ nguồn và đích trong tiêu đề IP.
- Một ví dụ về tiêu đề IP từ trang web Network Sorcery được hiển thị trong ảnh chụp màn hình. (Hình ảnh tiêu đề IP)
- Giải mã toàn bộ tiêu đề IP, ngoại trừ trường Options và trích xuất kiểu giao thức, địa chỉ nguồn và địa chỉ đích IP. Sử dụng module ctypes của Python để tạo một cấu trúc kiểu C để cho phép chúng ta có một định dạng thân thiện để xử lý tiêu đề IP và các trường của nó, như được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong trình soạn thảo văn bản)
import socket
import os
import struct
# host to listen on
host = "192.168.1.101"
# our IP header
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_ulong),
("dst", c_ulong)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
# map protocol constants to their names
self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
# human readable IP addresses
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
# human readable protocol
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num)
Use code with caution.Python
- Tạo một chương trình sniffer hoàn chỉnh giải mã tiêu đề như được hiển thị trong ảnh chụp màn hình, vì vậy bạn không phải đọc binary. Binary này được biểu thị bằng hex, không phải là thách thức hoàn toàn. (Hình ảnh mã trong trình soạn thảo văn bản)
import socket
import os
import struct
from ctypes import *
# host to listen on
host = "192.168.1.101"
# our IP header
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_ulong),
("dst", c_ulong)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
# map protocol constants to their names
self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
self.src_address = socket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = socket.inet_ntoa(struct.pack("<L",self.dst))
try:
self.protocol = self.protocol_map[self.protocol_num]
except:
self.protocol = str(self.protocol_num)
#create a raw socket and bind it to the public interface
if os.name == "nt":
socket_protocol = socket.IPPROTO_IP
else:
socket_protocol = socket.IPPROTO_ICMP
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
#we want the ip headers included in the capture
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# if we're using windows, we need to send an IOCTL
#to setup promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
try:
while True:
#read in a packet
raw_buffer = sniffer.recvfrom(65565)[0]
# create an IP header from the first 20 bytes of the buffer
ip_header = IP(raw_buffer[0:20])
# print out the protocol that was detected and the hosts
print "Protocol: %s %s -> %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)
#handle CTRL-C
except KeyboardInterrupt:
# if we're using windows, turn off promiscuous mode
if os.name == "nt":
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
Use code with caution.Python
- Để giải thích rõ hơn, trước tiên, phương thức __init__ (trong trường hợp này, bạn nhận được từ mạng) sẽ tải new data vào cấu trúc đã được tạo. Lớp đơn giản sẽ tạo hiệu quả IP buffer khi tải new data vào bên trong.
- Thêm mã để liên tục đọc và phân tích các packet được đưa vào. Đầu ra sẽ bao gồm giao thức ICMP, địa chỉ nguồn và địa chỉ đích, như được hiển thị trong ví dụ:
- Protocol: ICMP 74.125.226.78 -> 192.168.0.190
- Khi số lượng hoạt động tăng lên, quá trình tạo các tập lệnh của riêng bạn trở nên đơn điệu. Cân nhắc sử dụng.
- Trước khi viết kịch bản, hãy khám phá công cụ sudo scapy. (Hình ảnh màn hình terminal)
- Đây là một trình thông dịch tương tác, tương tự như giao diện Python.
- Bắt đầu với một packet ping cơ bản. Đầu tiên, hãy khám phá cách xác định cấu trúc bạn cần. Như bạn có thể thấy, bạn đang sử dụng khả năng của công cụ để trích xuất các trường mặc định. Một ví dụ về đầu ra từ cái này được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Đây là sức mạnh của công cụ. Bạn chỉ cần cung cấp cấu trúc để viết kịch bản.
- Nhập các lệnh bên dưới vào cửa sổ terminal — chỉ thay thế địa chỉ IP bằng địa chỉ cho mạng của bạn. Ngoài ra, nếu bạn có kết nối internet “trực tiếp”, hãy thay thế bằng trang web bạn chọn. Các lệnh vẫn giống nhau.
- 192.168.177.157 là địa chỉ IP của máy WinPy-Python.
- p = IP(dst=”192.168.177.157″)/ICMP()
- r = sr1(p) (Hình ảnh màn hình terminal hiển thị kết quả)
- Bạn đã gửi một packet ICMP đến đích được biểu diễn bằng dst, sau đó hiển thị chuỗi hồi đáp cho đến khi bạn gọi r[IP].src, sau đó địa chỉ nguồn sẽ được hiển thị.
- Đây là một công cụ cực kỳ mạnh mẽ và là một công cụ mà bạn nên đưa vào kho vũ khí của mình. Tiếp theo, chỉ định loại ICMP. Nhập mã sau:
- 192.168.177.200 là địa chỉ IP của máy Web-Python.
- p[dst=”192.168.177.200″]/ICMP(type=”echo-request”)
- Điều này cho phép bạn xác minh các packet.
- Sử dụng điều này trong quá trình thử nghiệm để kiểm tra xem hệ thống giám sát có phát hiện các packet bạn đang gửi hay không.
- Sau đó, hãy nhập p để in biến đã lưu trữ dữ liệu. (Hình ảnh màn hình terminal)
- Tạo packet bằng cách sử dụng ký hiệu /. Mỗi lớp được phân tách bằng ký hiệu /.
- Để xác minh packet đã được lắp ráp chính xác, hãy in packet và kiểm tra packet đó là chính xác.
- Truy cập từng lớp của packet tương tự như cách bạn truy cập vào các giá trị của một mảng bằng cách chỉ định index của mảng theo cùng một cách. Truy cập vào các giá trị của mỗi lớp sẽ như truy cập vào giá trị bên trong của một cấu trúc. Các phương thức của Scapy đã giúp việc này khá đơn giản. Trong các ví dụ bên dưới, bạn sẽ xem qua từng lớp và bắt đầu tạo packet và tương tác với chúng.
- Bây giờ bạn đã quen thuộc với shell, hãy bắt đầu tạo packet và tương tác với chúng.
- Các bài kiểm tra mạng không có Scapy rất đơn điệu và khó khăn để thực hiện một số thành phần nhất định. Xem xét hai ví dụ mà bạn rất khó thực hiện mà không có Scapy.
- Gửi một TCP segment với tối đa maximum segment size (MSS) lên đến 0 là một bài kiểm tra mạng thú vị để thực hiện với Scapy, nhưng sẽ mất nhiều dòng lệnh để hoàn thành mà không có Scapy. Bạn có thể đạt được điều này trong một dòng với Scapy.
- Nhập lệnh sau:
- send(IP(dst=”192.168.177.157″)/TCP(dport=5005, options=[(‘MSS’,50)]) (Hình ảnh màn hình terminal)
- Bạn đã tạo một packet TCP có kích thước 0 byte và gửi đến một cổng đích. Ví dụ: cổng đã được sửa đổi. Bạn có thể sử dụng điều này để kiểm tra xem hệ thống nhúng có phản hồi hay không hoặc một chuẩn không tuân thủ nào, vì việc kiểm tra khá phức tạp.
- Từ lệnh trên, bạn có thể gửi packet tùy chỉnh vào mạng, mặc dù điều này nằm ngoài phạm vi của phương pháp này.
- Phương pháp còn lại là fuzz(). Nếu bạn không có quyền truy cập internet, điều này sẽ không hiển thị. (Hình ảnh màn hình terminal)
- Bây giờ chúng ta hãy khám phá thêm một số ví dụ về công cụ này. Với Scapy, mỗi lớp mạng là một lớp Python. Toán tử / được sử dụng để liên kết các lớp lại với nhau. Đặt TCP lên trên IP, sau đó đặt IP lên trên Ethernet. Nhập lệnh sau:
- IP(src=”192.168.0.1″, dst=”192.168.0.10″)/TCP() (Hình ảnh màn hình terminal)
- Bây giờ bạn đã có cấu trúc của packet trong phần tóm tắt. Các mục màu đỏ bạn đã cung cấp và Scapy sẽ hoàn thành phần còn lại.
tiếp theo :
.
50. Để biết các trường nào, hãy nhập ls(IP, verbose=True). (Hình ảnh màn hình terminal)
51. Nhập p = Ether()/IP(dst=”192.168.177.157″)/TCP(). (Hình ảnh màn hình terminal)
52. Có nhiều phương thức hữu ích trong Scapy, chẳng hạn như hàm summary. Nhập p.summary(). Một ví dụ về đầu ra được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
53. Bạn sẽ thấy rằng Scapy có các tính năng thú vị. Một trong những phương pháp để cố gắng vượt qua bộ lọc là quét cổng nguồn. Scapy tự động giả vờ là lưu lượng truy cập đến từ máy chủ File Transfer Protocol (FTP). Ngoài ra, cổng mặc định mà Scapy chọn là cổng 80.
54. Khi bạn xem lại hình ảnh của cấu trúc, bất kỳ cấu trúc nào trong số này đều có thể được tham chiếu. Để các trường hiển thị, bạn có thể sử dụng kết hợp cấu trúc và phương thức thư viện. Nhập print(p.sprintf(“%Ether.src% > %Ether.dst%\n%IP.src% > %IP.dst%”)). (Hình ảnh màn hình terminal)
55. Hàm “sr1()” gửi một packet và trả về câu trả lời tương ứng. srp1() thực hiện tương tự cho các packet lớp hai, tức là Ethernet. Nếu bạn chỉ quan tâm đến việc gửi packet, hãy sử dụng hàm “send()”.
56. Ngoài ra, Scapy có thể sử dụng socket của hệ điều hành để gửi và nhận packet. (Hình ảnh mã trong trình soạn thảo văn bản)
import socket
#create a socket object
sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#connect to google public dns
sck.connect(("8.8.8.8", 53))
#create StreamSocket
ssck = StreamSocket(sck)
#use DNS
ssck.basecls=DNS
#send and receive dns query
anwser = ssck.sr1(IP(dst="www.eccouncil.org")/UDP()/DNS(rd=1, qd=DNSQR(qname="www.eccouncil.org")))
print anwser
Use code with caution.Python
- Một ví dụ về đầu ra được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Mã tạo một socket UDP để truy vấn địa chỉ EC-Council dựa trên tham chiếu đến DNS công cộng của Google. Lý do bạn trình diễn UDP ở đây là khi bạn sử dụng UDP, Scapy có thể tạo socket mà không cần quyền root. Điều này rất quan trọng vì nếu bạn ở trên hộp, bạn có thể tải Scapy và tạo socket UDP mà không cần quyền root.
- Hơn nữa, Scapy có thể mở rộng các giao thức — ví dụ: bạn có thể thiết lập DNS qua TCP. Điều này có thể thực hiện được do tính kế thừa của lớp; đó là một trong những thành phần phổ biến để tận dụng trong lập trình hướng đối tượng. (Hình ảnh mã trong trình soạn thảo văn bản)
class DNSTCP(Packet):
name = "DNS over TCP"
fields_desc=[ FieldLenField("len", None, fmt="!H", length_of="dns"),
PacketLenField("dns", DNS, length_from=lambda p:p.len)]
def guess_payload_class(self, payload):
return DNSTCP
Use code with caution.Python
- Vì DNS được phép chủ yếu trên các mạng, bạn có thể sử dụng điều này để gửi tin nhắn và sử dụng TCP.
- Một tính năng mạnh mẽ khác của Scapy là tự động hóa, cho phép trừu tượng hóa. Một ví dụ về TCP Scanner tận dụng điều này được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong trình soạn thảo văn bản)
#!/usr/bin/env python
from scapy.all import *
conf.verb = 0 # enable verbose mode - Is this actually enabling?
ports = [25,80,53,443,445,8080,8443]
def SynScan(host):
ans,unans=sr(IP(dst=host)/TCP(dport=ports,flags="S"))
print("Open ports at %s:" % host)
for (s,r,) in ans:
if s[TCP].dport == r[TCP].sport and r[TCP].flags == 0x12: # is 0x12 SYN/ACK?
print(str(s[TCP].dport))
print("Closed ports at %s:" % host)
for (s,r,) in ans:
if s[TCP].dport == r[TCP].sport and r[TCP].flags == 0x14: # is 0x14 RST/ACK?
print(str(s[TCP].dport))
host = "192.168.1.100"
SynScan(host)
Use code with caution.Python
- Có nhiều tùy chọn để xây dựng và thực hiện các tác vụ khác với công cụ này.
- Một bảng liệt kê một số lệnh và tác dụng của chúng được hiển thị trong ảnh chụp màn hình. (Hình ảnh bảng lệnh Scapy)
- Một ví dụ bổ sung cho việc gửi packet được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong trình soạn thảo văn bản)
>>> send(IP(dst="1.2.3.4")/ICMP())
.
Sent 1 packets.
>>> sendp(Ether()/IP(dst="1.2.3.4",ttl=(1,4)),iface="eth0")
.
Sent 4 packets.
>>> sendp([IP(dst="1.2.3.4")/ICMP(),IP(dst="www.google.com")/TCP(dport=25)],iface="eth0")
Sent 2 packets.
Use code with caution.Python
- Scapy cũng cho phép fuzzing do tính năng “fuzz()” của nó. Nhập send(IP(dst=”192.168.177.157″)/fuzz(UDP)/NTP(version=4)),loop=1). (Hình ảnh màn hình terminal)
- Trong ví dụ này, bạn đã fuzzing gần 4902 packet và gửi chúng vào cổng UDP của NTP 123.
- Điều này cho phép bạn nhanh chóng xây dựng các mẫu fuzzing và gửi chúng trong một vòng lặp.
- Tiếp theo, khám phá một ví dụ về sr(), cho phép bạn gửi và nhận. Nhập sr(IP(dst=”192.168.177.157″)/TCP(dport=[53,80,3306,60000])). (Hình ảnh màn hình terminal)
- Dữ liệu có thể được truy xuất bằng cách sử dụng summary(), như được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Danh sách các hàm đã có sẵn trong Scapy được hiển thị trong ảnh chụp màn hình. (Hình ảnh danh sách hàm Scapy)
- Bây giờ bạn đã quen thuộc với cả Python và Scapy, đó là những công cụ tuyệt vời để kiểm tra. Điều này kết thúc bài tập thực hành.
Bài tập 3: Kịch bản Python trên Windows và Liệt kê
Mục tiêu:
- Tạo kịch bản Python và khám phá việc liệt kê Windows.
- Trong bài thực hành này, bạn sẽ tạo một số kịch bản Python đơn giản. Đầu tiên, bạn sẽ thực hiện liệt kê máy Windows với hàm “wmi python”. Nhấp vào WinPy-Python và sau đó nhấp vào Ctrl+Alt+Delete.
- Trong trường Mật khẩu, hãy nhập Pa w0rd và nhấn Enter. (Hình ảnh màn hình đăng nhập Windows)
- Mở File Explorer và điều hướng đến C:\Program Files và shift + nhấp chuột phải vào thư mục Python39 và chọn Open PowerShell window here như được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình Windows)
- Trong cửa sổ PowerShell, nhập các lệnh sau như được hiển thị trong ảnh chụp màn hình:
- python
- import wmi
- conn = wmi.WMI()
- for class_name in conn.classes:
- if ‘Process’ in class_name:
- print(class_name) (Hình ảnh màn hình PowerShell)
- Nhấn Enter hai lần. Đảm bảo bạn làm theo các thụt đầu dòng. (Hình ảnh màn hình PowerShell)
- Để truy vấn thông tin hệ thống cụ thể, hãy xác định lớp Windows Management Instrumentation (WMI) có thể cung cấp thông tin liên quan. Sử dụng thuộc tính “classes” của đối tượng WMI như wmi.WMI().classes, sẽ trả về danh sách các lớp WMI.
- Ngay cả khi bạn biết tên của lớp WMI, bạn vẫn sẽ yêu cầu tên chính xác của thuộc tính mà các lớp này cung cấp và các phương thức có thể thực hiện các thao tác cụ thể. Quá trình và các bước để lấy dữ liệu này bao gồm sử dụng toán tử “.”. Đây là một phương pháp phổ biến để trích xuất các thành phần khác nhau trong các lớp.
- Để đạt được điều này, hãy nhập lệnh sau và nhấn Enter:
- wmi.WMI().Win32_Process.methods.keys() (Hình ảnh màn hình PowerShell)
- Lệnh in tất cả các thuộc tính từ lớp WMI; bây giờ bạn phải xem xét các phương thức. Nhập wmi.WMI().Win32_Process.properties.keys() và nhấn Enter. (Hình ảnh màn hình PowerShell)
- Khi bạn đã biết các thuộc tính và phương thức của lớp “Win32_Process”, hãy sử dụng tên lớp WMI theo sau là dấu ngoặc mở và đóng để trả về các đối tượng của lớp WMI. Nhập các lệnh sau:
- conn = wmi.WMI()
- for process in conn.Win32_Process():
- print(“ID: {0}\nHandleCount: {1}\nProcessName: {2}\n”.format(process.ProcessId, process.HandleCount, process.Name)) (Hình ảnh màn hình PowerShell)
- Nhấn Enter hai lần. Đảm bảo bạn làm theo các thụt đầu dòng. (Hình ảnh màn hình PowerShell)
- Bạn cũng có thể liệt kê các dịch vụ đang chạy bằng mã, như được hiển thị trong ảnh chụp màn hình.
- import wmi
- conn = wmi.WMI()
- for s in conn.Win32_Service(StartMode=”Auto”, State=”Running”):
- print(s.State, s.StartMode, s.Name, s.DisplayName) (Hình ảnh màn hình PowerShell)
- Trong ví dụ tiếp theo, lọc ra tất cả các dịch vụ Windows đã dừng; trong chế độ khởi động “Automatic”, sau đó sử dụng phương thức “StartService()” để khởi động dịch vụ Windows. Trong trường hợp bạn muốn dừng dịch vụ, bạn có thể sử dụng phương thức “StopService()”.
- import wmi
- conn = wmi.WMI()
- for s in conn.Win32_Service(StartMode=”Auto”, State=”Stopped”):
- if ‘Update’ in s.Name:
- result, = s.StartService()
- if result == 0:
- print(“Successfully started service:”, s.Name)
- Sử dụng hàm wmi, bạn có thể trích xuất những điều sau:
- Tên miền mạng
- MAC giao diện
- IP giao diện
- Mặt nạ mạng con
- Hồ sơ hệ thống
- Hoạt động hệ thống
- Kiến trúc
- Tên máy tính
- Người dùng đã đăng ký
- Ảnh chụp màn hình hiển thị mã để thực hiện tác vụ này. Bạn có thể nhập mã để hoàn thành tác vụ này hoặc bạn có thể xem lại đầu ra. Thu nhỏ cửa sổ notepad++. (Hình ảnh mã trong Notepad++)
import wmi
try:
for netParams in wmi.WMI().Win32_NetworkAdapterConfiguration():
if netParams.MACAddress != None and netParams.IPAddress != None and netParams.IPSubnet != None:
if netParams.DNSDomain != None:
print ("Domain: ", netParams.DNSDomain)
print ("mac: ", netParams.MACAddress.lower())
print ("ip: ", netParams.IPAddress[0])
print ("mask", netParams.IPSubnet[0])
for profileParams in wmi.WMI().Win32_NetworkLoginProfile():
if profileParams.Name != None:
print ("Profile: ", profileParams.Name)
for SOParams in wmi.WMI().Win32_OperatingSystem():
print ("Operation System: ", SOParams.Caption)
print ("Computer Name: ", SOParams.CSName)
print ("Architecture: ", SOParams.OSArchitecture)
print ("User Registered: ", SOParams.RegisteredUser)
except Exception as e:
print (e)
Use code with caution.Python
- Bây giờ, hãy khởi chạy một dấu nhắc lệnh và nhập python C:\Users\Admin\Desktop\enumwin.py và nhấn Enter. Đầu ra và kết quả từ lệnh được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình dấu nhắc lệnh)
Bạn cũng có thể sử dụng wmi để kết nối với máy tính từ xa nếu bạn đang kiểm tra từ xa. Để làm điều này, bạn nhập lệnh sau: conn = wmi.WMI(“192.168.177.1″, user=”username”, password=”P@ssw0rd@123″)
- Khám phá thêm một khả năng. Đối với điều này, bạn sẽ sử dụng Python 3. Hãy nhớ rằng, luôn luôn tốt để thử nghiệm và kiểm tra kịch bản của bạn với các phiên bản khác nhau. Điều này là do, nếu bạn đang ở trên máy của riêng mình, bạn sẽ quen thuộc với phiên bản, tương ứng với các hàm và phương thức cụ thể. Tuy nhiên, luôn luôn thử nghiệm với các phiên bản khác nhau trong trường hợp bạn gặp phải phiên bản khác với phiên bản của riêng bạn. Nên có nhiều phiên bản Python trên máy thử nghiệm. Tạo một tệp chứa mã được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã trong Notepad++)
from scapy.all import ARP, Ether, srp
target_ip = "192.168.1.1/24" # replace the ip address with the network you want to use.
# IP Address for the destination
# create ARP packet
arp = ARP(pdst=target_ip)
# create the Ether broadcast packet
# ff:ff:ff:ff:ff:ff MAC address indicates broadcasting
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
# stack them
packet = ether/arp
result = srp(packet, timeout=3, verbose=0)[0]
# a list of clients, we will fill this in the upcoming loop
clients = []
for sent, received in result:
# for each response, append ip and mac address to `clients` list
clients.append({'ip': received.psrc, 'mac': received.hwsrc})
# print clients
print("Available devices in the network:")
print("IP" + " "*18+"MAC")
for client in clients:
print("{:16} {}".format(client['ip'], client['mac']))
Use code with caution.Python
- Xem lại mã và đầu ra từ mã đang được sử dụng, như được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình dấu nhắc lệnh)
- Bạn có thể cải thiện trình quét cổng bằng cách thêm màu vào đầu ra. (Hình ảnh mã trong Notepad++)
import socket
from colorama import init, Fore
# some colors
init()
GREEN = Fore.GREEN
RESET = Fore.RESET
GRAY = Fore.LIGHTBLACK_EX
def is_port_open(host, port):
""" determine whether `host` has the `port` open """
# creates a new socket
s = socket.socket()
try:
# tries to connect to host using that port
s.connect((host, port))
# make timeout if you want it a little faster (less accuracy)
# s.settimeout(0.2)
except:
# cannot connect, port is closed
return False
else:
# the connection was established, port is open!
return True
# get the host from the user
host = input("Enter the host:")
# iterate over ports, from 1 to 1024
for port in range(1, 1025):
if is_port_open(host, port):
print(f"{GREEN}[+] {host}:{port} is open {RESET}")
else:
print(f"{GRAY}[+] {host}:{port} is close {RESET}", end="\r")
Use code with caution.Python
- Bạn sẽ sử dụng module colorama để cung cấp đầu ra màu. Mã cho trình quét được hiển thị trong ảnh chụp màn hình.
- Một ví dụ về đầu ra có màu được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình dấu nhắc lệnh)
- Bạn sẽ thấy rằng trình quét chậm vì bạn không sử dụng các khái niệm đa luồng. Để tăng tốc độ, bạn cần thêm các luồng. (Hình ảnh mã trong trình soạn thảo văn bản)
def main(host, ports):
global q
for t in range(N_THREADS):
t = Thread(target=scan_thread)
# when we set daemon to true, that thread will end when the main thread ends
t.daemon = True
# start the daemon thread
t.start()
for worker in ports:
# for each port, put that port into the queue
# to start scanning
q.put(worker)
# wait the threads (port scanners) to finish
q.join()
Use code with caution.Python
- Bạn có thể sử dụng các kỹ thuật và hàm khác nhau trong Python hoặc trong các công cụ đã được phát triển trong Python.
- Điều này kết thúc bài tập thực hành.
Bài tập 4: Cạo web Python
Mục tiêu:
- Sử dụng kịch bản Python để trích xuất dữ liệu từ một trang web
Thời gian thực hành: 20 phút
- Trong bài thực hành này, bạn sẽ tạo một số kịch bản Python đơn giản tận dụng các thư viện khác nhau và bạn sẽ khám phá công cụ BeautifulSoup. BeautifulSoup có các hàm cho phép bạn trích xuất dữ liệu lớn với ít nỗ lực.
- BeautifulSoup là một thư viện Python được thiết kế cho các dự án nhanh chóng như cạo màn hình.
- Có ba thành phần chính của công cụ:
- Beautiful Soup cung cấp một vài phương thức đơn giản và thành ngữ Pythonic để điều hướng, tìm kiếm và sửa đổi cây phân tích cú pháp. Nó là một bộ công cụ để phân tích một tài liệu và trích xuất những gì bạn cần. Không mất nhiều mã để viết một ứng dụng.
- Beautiful Soup tự động chuyển đổi các tài liệu đến thành Unicode và các tài liệu đi thành UTF-8. Bạn không cần phải nghĩ về mã hóa, trừ khi tài liệu không chỉ định mã hóa. Hơn nữa, Beautiful Soup không thể phát hiện ra một. Trong trường hợp này, bạn chỉ cần chỉ định mã hóa ban đầu. Beautiful Soup nằm trên các trình phân tích cú pháp Python phổ biến.
- Quá trình ở đây liên quan đến việc đưa dữ liệu vào công cụ, sau đó phân tích cú pháp và trích xuất dữ liệu.
- Dữ liệu có giá trị đã từng bị khóa trong các trang web được thiết kế kém hiện đã nằm trong tầm tay của bạn. Các dự án sẽ mất hàng giờ chỉ mất vài phút với Beautiful Soup.
- Theo mặc định, máy Python-Machine được chọn. Nếu bạn đã đăng nhập, hãy bỏ qua bước 7. (Hình ảnh màn hình đăng nhập Ubuntu)
- Chúng ta hãy xem xét phương pháp cho bài tập này bằng cách sử dụng thư viện Python 3. Trong một terminal mới, hãy nhập mã được hiển thị trong ảnh chụp màn hình.
- 192.168.177.200 là địa chỉ IP của máy Web-Python.
- python3
- import requests
- page = requests.get(“http://192.168.177.200”) (Hình ảnh màn hình terminal)
- Sau khi chạy yêu cầu, bạn sẽ nhận được một đối tượng Phản hồi. Đối tượng này có thuộc tính status_code, cho biết liệu trang có được tải xuống thành công hay không. Nhập lệnh sau:
- page.status_code (Hình ảnh màn hình terminal)
- Mã trạng thái bắt đầu bằng 2 thường biểu thị thành công và mã bắt đầu bằng 4 hoặc 5 biểu thị lỗi.
- In nội dung của trang với hàm nội dung được đặt tên thích hợp. Trong cửa sổ terminal, nhập page.content. Một ví dụ về đầu ra của lệnh này được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Những dữ liệu này ở định dạng “thô” cực kỳ; bạn có thể sử dụng BeautifulSoup để phân tích cú pháp và làm sạch chúng. Trong trình thông dịch Python, nhập các lệnh sau:
- from bs4 import BeautifulSoup
- soup = BeautifulSoup(page.content, ‘html.parser’) (Hình ảnh màn hình terminal)
- Quá trình làm sạch đầu ra được đặt tên thích hợp là prettify. Bây giờ bạn có thể in nội dung HTML của trang, được định dạng đầy đủ, bằng cách sử dụng phương thức prettify trên đối tượng BeautifulSoup. Nhập lệnh sau:
- print(soup.prettify()) (Hình ảnh màn hình terminal)
- Vì tất cả các thẻ được lồng nhau, bạn có thể di chuyển qua cấu trúc từng cấp độ một. Chọn tất cả các phần tử ở cấp cao nhất của trang bằng cách sử dụng thuộc tính children của soup. Lưu ý rằng children trả về một trình tạo danh sách, vì vậy bạn cần gọi hàm list trên đó.
- Trong trình thông dịch, hãy nhập lệnh sau:
- list(soup.children) (Hình ảnh màn hình terminal)
- Lệnh sẽ xuất tất cả dữ liệu từ danh sách đã được tạo.
- Sử dụng lệnh sau để trích xuất các phần tử BeautifulSoup: [type(item) for item in list(soup.children)]. (Hình ảnh màn hình terminal)
- Tất cả các mục đều là đối tượng BeautifulSoup. Mục đầu tiên được khai báo là một lớp; trong trường hợp này, bạn có một loạt các loại phần tử chuỗi khác nhau.
- Nếu bạn thực hiện các bước từ trước đó, bạn có thể trích xuất các mục hoặc dữ liệu cụ thể. Nhập lệnh sau:
- soup.findAll(‘a’)
- Lệnh sẽ trích xuất tất cả các mục có ký tự “a”. (Hình ảnh màn hình terminal)
- Bạn đã trích xuất tất cả các mục có ký tự “a” trong đó. Để trích xuất một tập hợp con nhỏ hơn, hãy nhập lệnh sau:
- soup.find(‘a’) (Hình ảnh màn hình terminal)
- Đầu ra hiển thị cho chúng ta một mục một dòng.
- Một điều khác cần tìm là phần đầu của các đoạn văn. Nhập lệnh sau:
- soup.findAll(‘p’) (Hình ảnh màn hình terminal)
- Bạn sẽ sử dụng các hàm khác nhau để cạo dữ liệu từ các trang web; điều này phụ thuộc vào cách trang web được xây dựng.
- Một phương thức khác để trích xuất liên kết là bằng cách sử dụng các lệnh sau:
- for url in soup.find_all(‘a’):
- print(url.get(‘href’)) (Hình ảnh màn hình terminal)
- Nếu bạn chỉ muốn lấy văn bản, hãy nhập print(soup.get_text()). (Hình ảnh màn hình terminal)
- Chúng ta có thể truy cập soup.body để lấy phần thân. Sau đó, lấy .text từ đó bằng cách sử dụng chuỗi lệnh sau:
- body = soup.body
- for paragraph in body.find_all(‘a’):
- print(paragraph.text) (Hình ảnh màn hình terminal)
- Phương pháp tốt nhất để thực hành với công cụ này là tạo một trang web, sau đó truy vấn các tham số khác nhau để mang lại kết quả.
- Nhập mã HTML và lưu dưới dạng sample.html, như được hiển thị trong ảnh chụp màn hình. (Hình ảnh mã HTML trong Leafpad)
<!DOCTYPE html>
<html>
<head>
<title>Header</title>
<meta charset="utf-8">
</head>
<body>
<h2>Operating Systems</h2>
<ul id="mylist" style="width:150px">
<li>OpenBSD</li>
<li>FreeBSD</li>
<li>Debian</li>
<li>NetBSD</li>
<li>Windows</li>
</ul>
<p>
FreeBSD is an advanced computer operating system used to power modern servers, desktops, and embedded platforms.
</p>
<p>
Debian is a Unix-like computer operating system that is composed entirely of free software.
</p>
</body>
</html>
Use code with caution.Html
- Bây giờ bạn đã tạo một trang HTML đơn giản để trích xuất dữ liệu. Sau đó, nhập mã Python sau vào một tệp và lưu dưới dạng souptest.py trên Desktop:
- #!/usr/bin/python3
- from bs4 import BeautifulSoup
- with open(“yourname.html”, “r”) as f:
`contents = f.read()`
Use code with caution.
`soup = BeautifulSoup(contents, 'lxml')`
Use code with caution.
`print(soup.h2)`
Use code with caution.
`print(soup.head)`
Use code with caution.
`print(soup.li)`
-
- Use code with caution.
- Mã được chia nhỏ như sau: In mã HTML của ba thẻ từ dữ liệu được trích xuất trong tệp. Vì lần này bạn đã cung cấp tệp, nên việc quan sát chức năng của các lệnh khác nhau sẽ dễ dàng hơn. Một đối tượng BeautifulSoup được tạo; dữ liệu HTML được chuyển đến hàm tạo. Tùy chọn thứ hai chỉ định trình phân tích cú pháp.
- Trong cửa sổ terminal nơi tệp được đặt, hãy nhập python souptest.py. Một ví dụ về đầu ra của lệnh này được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Sửa đổi mã, để nó trích xuất các thẻ và văn bản. Thuộc tính name của một thẻ cho biết tên của nó và thuộc tính text cho biết nội dung văn bản của nó. Thay thế mã cho câu lệnh in trong mã của bạn, như được hiển thị ở đây: (Hình ảnh mã trong Leafpad)
#!/usr/bin/python3
from bs4 import BeautifulSoup
with open("sample.html", "r") as f:
contents = f.read()
soup = BeautifulSoup(contents, 'lxml')
print("HTML: {0}, name: {1}, text: {2}".format(soup.h2, soup.h2.name, soup.h2.text))
Use code with caution.Python
- Khi bạn đã thực hiện các thay đổi mã và lưu tệp, hãy thực thi mã và xem lại đầu ra, như được hiển thị trong ảnh chụp màn hình. (Hình ảnh màn hình terminal)
- Để trích xuất tất cả các thẻ, hãy sử dụng khả năng đệ quy để thực hiện việc này. Một lần nữa, hãy thay thế phần in bằng mã sau:
- for child in soup.recursiveChildGenerator():
`if child.name:`
Use code with caution.
`print(child.name)`
- Use code with caution.
Khi bạn đã thực hiện các thay đổi mã, bây giờ bạn có lệnh gọi đi qua cây tài liệu và in tên của tất cả các thẻ HTML. (Hình ảnh mã trong Leafpad)
Đoạn mã này cực kỳ mạnh mẽ. Chỉ với một vài dòng, bây giờ bạn có khả năng trích xuất tất cả các thẻ từ trang web, điều này rất hữu ích cho các hoạt động kiểm tra thâm nhập.
Tiếp tục và khám phá công cụ. Bạn có thẻ cho trẻ em, như được hiển thị trong dòng mã tiếp theo:
- root_childs = [e.name for e in root.children if e.name is not None]
Bạn cũng có thể trích xuất con cháu, như được hiển thị trong dòng mã tiếp theo. Lấy tất cả con cháu (con của tất cả các cấp) của một thẻ:
- root_childs = [e.name for e in root.descendants if e.name is not None]
Để xem điều này trong mã, hãy thêm hai dòng tiếp theo vào tập lệnh python, sau đó chạy nó:
- root_childs = [e.name for e in root.descendants if e.name is not None]
- print(root_childs)
Trong trình soạn thảo văn bản bạn chọn, hãy nhập mã sau:
- #!/usr/bin/python3
- from bs4 import BeautifulSoup
- import requests as req
- resp = req.get(“http://192.168.177.200”)
- soup = BeautifulSoup(resp.text, ‘lxml’)
- print(soup.title)
- print(soup.title.text)
- print(soup.title.parent) (Hình ảnh mã trong trình soạn thảo văn bản)
Một ví dụ về đầu ra của tập lệnh được hiển thị bên dưới sau khi nó chạy trên trang chủ của máy ảo OWASP Broken Web Applications (BWA). (Hình ảnh màn hình terminal)
Điều này kết thúc bài tập thực hành.





Bình luận về bài viết này