“This is the ninth day of my participation in the First Challenge 2022. For details: First Challenge 2022”

The Tidal open source version is made use of fOFA’s banner

First, tidal defines a CMS list of CMS_finger_list, which is the same as the data in the SQllite data table.

And then when the following thing, temporarily did not understand what is dry

self.W = '\033[0m'
self.G = '\033[1;32m'
self.R = '\033[1;31m'
self.O = '\033[1;33m'
self.B = '\033[1;34m'
Copy the code

And this tidal fingerprinting is based on THE HTTP protocol, rather than a host port scan. Although the current analysis of the code is I rewrite again, but basically nothing changed, now to analyze.

cms = Cmsscanner(target_url, self.request_timeout, self.pwd)
fofa_finger = cms.run()
Copy the code

Let’s see Cmsscanner

def __init__(self, *params) :
    self.target, self.request_timeout, self.pwd = params
    self.start = time.time()
    self.finger = []
    self.agent = {'UserAgent': 'the Mozilla / 5.0 (Windows; U; MSIE 9.0; WIndows NT 9.0; en-US))'}
    self.rtitle = re.compile(r'title="(.*)"')
    self.rheader = re.compile(r'header="(.*)"')
    self.rbody = re.compile(r'body="(.*)"')
    self.rbracket = re.compile(r'\((.*)\)')
Copy the code

The run method is called as follows

def run(self) :
    try:
        header, body, title = self.get_info()
        for _id in range(1.int(self.count())):
            try:
                self.handle(_id, header, body, title)
            except Exception as e:
                pass
    except Exception as e:
        print(e)
    finally:
        return self.finger
Copy the code

It calls the git_info method, so let’s see what it does

def get_info(self) :
    """ Get information on the Web. ""
    try:
        r = requests.get(url=self.target, headers=self.agent,
                         timeout=self.request_timeout, verify=False)
        content = r.text
        try:
            title = BS(content, 'lxml').title.text.strip()
            return str(r.headers), content, title.strip('\n')
        except:
            return str(r.headers), content, ' '
    except Exception as e:
        pass
Copy the code

Use the GET method to make a normal request to the target and get the result, mainly containing the content, title and response header. Then the run method iterates through each fingerprint in the database again for processing. Take a closer look at the Handle method

def handle(self, _id, header, body, title) :
    """ Retrieve database key to match """ "
    name, key = self.check(_id)
    # a situation where only one condition is satisfied
    if '| |' in key and '&' not in key and '(' not in key:
        for rule in key.split('| |') :if self.check_rule(rule, header, body, title):
                self.finger.append(name)
                # print '%s[+] %s %s%s' % (G, self.target, name, W)
                break
    # Only one condition
    elif '| |' not in key and '&' not in key and '(' not in key:
        if self.check_rule(key, header, body, title):
            self.finger.append(name)
            # print '%s[+] %s %s%s' % (G, self.target, name, W)
    # Condition where both conditions need to be met
    elif '&' in key and '| |' not in key and '(' not in key:
        num = 0
        for rule in key.split('&') :if self.check_rule(rule, header, body, title):
                num += 1
        if num == len(key.split('&')):
            self.finger.append(name)
            # print '%s[+] %s %s%s' % (G, self.target, name, W)
    else:
        # and under the condition of existence and condition: 1 | | 2 | | (3 & 4)
        if '&' in re.findall(self.rbracket, key)[0] :for rule in key.split('| |') :if '&' in rule:
                    num = 0
                    for _rule in rule.split('&') :if self.check_rule(_rule, header, body, title):
                            num += 1
                    if num == len(rule.split('&')):
                        self.finger.append(name)
                        # print '%s[+] %s %s%s' % (G, self.target, name, W)
                        break
                else:
                    if self.check_rule(rule, header, body, title):
                        self.finger.append(name)
                        # print '%s[+] %s %s%s' % (G, self.target, name, W)
                        break
        else:
            And under the condition of existence and conditions: # 1 & 2 && (3 | | 4)
            for rule in key.split('&'):
                num = 0
                if '| |' in rule:
                    for _rule in rule.split('| |') :if self.check_rule(_rule, title, body, header):
                            num += 1
                            break
                else:
                    if self.check_rule(rule, title, body, header):
                        num += 1
            if num == len(key.split('&')):
                self.finger.append(name)
                # print '%s[+] %s %s%s' % (G, self.target, name, W)
Copy the code

What about the check_rule function for each rule

def check_rule(self, key, header, body, title) :
    """ fingerprint Identification """
    try:
        if 'title="' in key:
            if re.findall(self.rtitle, key)[0].lower() in title.lower():
                return True
        elif 'body="' in key:
            if re.findall(self.rbody, key)[0] in body: return True

        else:
            if re.findall(self.rheader, key)[0] in header: return True

    except Exception as e:
        pass
Copy the code

This essentially means looking for a regular expression rule in the title/header and body sections of the home page, and if so, finding one.